xref: /netbsd/external/mpl/bind/dist/lib/dns/name.c (revision 4ac1c27e)
1*4ac1c27eSchristos /*	$NetBSD: name.c,v 1.12 2023/01/25 21:43:30 christos Exp $	*/
2e2b1b9c0Schristos 
3e2b1b9c0Schristos /*
4e2b1b9c0Schristos  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
5e2b1b9c0Schristos  *
6c0b5d9fbSchristos  * SPDX-License-Identifier: MPL-2.0
7c0b5d9fbSchristos  *
8e2b1b9c0Schristos  * This Source Code Form is subject to the terms of the Mozilla Public
9e2b1b9c0Schristos  * License, v. 2.0. If a copy of the MPL was not distributed with this
1073584a28Schristos  * file, you can obtain one at https://mozilla.org/MPL/2.0/.
11e2b1b9c0Schristos  *
12e2b1b9c0Schristos  * See the COPYRIGHT file distributed with this work for additional
13e2b1b9c0Schristos  * information regarding copyright ownership.
14e2b1b9c0Schristos  */
15e2b1b9c0Schristos 
16e2b1b9c0Schristos /*! \file */
17e2b1b9c0Schristos 
18e2b1b9c0Schristos #include <ctype.h>
19f2e20987Schristos #include <inttypes.h>
20f2e20987Schristos #include <stdbool.h>
21e2b1b9c0Schristos #include <stdlib.h>
22e2b1b9c0Schristos 
23e2b1b9c0Schristos #include <isc/buffer.h>
24e2b1b9c0Schristos #include <isc/hash.h>
25e2b1b9c0Schristos #include <isc/mem.h>
26e2b1b9c0Schristos #include <isc/once.h>
27e2b1b9c0Schristos #include <isc/print.h>
28e2b1b9c0Schristos #include <isc/random.h>
29e2b1b9c0Schristos #include <isc/string.h>
30e2b1b9c0Schristos #include <isc/thread.h>
31e2b1b9c0Schristos #include <isc/util.h>
32e2b1b9c0Schristos 
33e2b1b9c0Schristos #include <dns/compress.h>
34e2b1b9c0Schristos #include <dns/fixedname.h>
35e2b1b9c0Schristos #include <dns/name.h>
36e2b1b9c0Schristos #include <dns/result.h>
37e2b1b9c0Schristos 
38e2b1b9c0Schristos #define VALID_NAME(n) ISC_MAGIC_VALID(n, DNS_NAME_MAGIC)
39e2b1b9c0Schristos 
40e2b1b9c0Schristos typedef enum {
41e2b1b9c0Schristos 	ft_init = 0,
42e2b1b9c0Schristos 	ft_start,
43e2b1b9c0Schristos 	ft_ordinary,
44e2b1b9c0Schristos 	ft_initialescape,
45e2b1b9c0Schristos 	ft_escape,
46e2b1b9c0Schristos 	ft_escdecimal,
47e2b1b9c0Schristos 	ft_at
48e2b1b9c0Schristos } ft_state;
49e2b1b9c0Schristos 
509742fdb4Schristos typedef enum { fw_start = 0, fw_ordinary, fw_newcurrent } fw_state;
51e2b1b9c0Schristos 
52e2b1b9c0Schristos static char digitvalue[256] = {
53e2b1b9c0Schristos 	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*16*/
54e2b1b9c0Schristos 	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*32*/
55e2b1b9c0Schristos 	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*48*/
56e2b1b9c0Schristos 	0,  1,	2,  3,	4,  5,	6,  7,	8,  9,	-1, -1, -1, -1, -1, -1, /*64*/
57e2b1b9c0Schristos 	-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*80*/
58e2b1b9c0Schristos 	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*96*/
59e2b1b9c0Schristos 	-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*112*/
60e2b1b9c0Schristos 	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*128*/
61e2b1b9c0Schristos 	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
62e2b1b9c0Schristos 	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
63e2b1b9c0Schristos 	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
64e2b1b9c0Schristos 	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
65e2b1b9c0Schristos 	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
66e2b1b9c0Schristos 	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
67e2b1b9c0Schristos 	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
68e2b1b9c0Schristos 	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*256*/
69e2b1b9c0Schristos };
70e2b1b9c0Schristos 
71e2b1b9c0Schristos static unsigned char maptolower[] = {
729742fdb4Schristos 	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
739742fdb4Schristos 	0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
749742fdb4Schristos 	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23,
759742fdb4Schristos 	0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
769742fdb4Schristos 	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
779742fdb4Schristos 	0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
789742fdb4Schristos 	0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73,
799742fdb4Schristos 	0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
809742fdb4Schristos 	0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b,
819742fdb4Schristos 	0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
829742fdb4Schristos 	0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83,
839742fdb4Schristos 	0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
849742fdb4Schristos 	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b,
859742fdb4Schristos 	0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
869742fdb4Schristos 	0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3,
879742fdb4Schristos 	0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
889742fdb4Schristos 	0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb,
899742fdb4Schristos 	0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
909742fdb4Schristos 	0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3,
919742fdb4Schristos 	0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
929742fdb4Schristos 	0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb,
939742fdb4Schristos 	0xfc, 0xfd, 0xfe, 0xff
94e2b1b9c0Schristos };
95e2b1b9c0Schristos 
96e2b1b9c0Schristos #define CONVERTTOASCII(c)
97e2b1b9c0Schristos #define CONVERTFROMASCII(c)
98e2b1b9c0Schristos 
99e2b1b9c0Schristos #define INIT_OFFSETS(name, var, default_offsets) \
100e2b1b9c0Schristos 	if ((name)->offsets != NULL)             \
101e2b1b9c0Schristos 		var = (name)->offsets;           \
102e2b1b9c0Schristos 	else                                     \
103e2b1b9c0Schristos 		var = (default_offsets);
104e2b1b9c0Schristos 
105e2b1b9c0Schristos #define SETUP_OFFSETS(name, var, default_offsets) \
1069742fdb4Schristos 	if ((name)->offsets != NULL) {            \
107e2b1b9c0Schristos 		var = (name)->offsets;            \
1089742fdb4Schristos 	} else {                                  \
109e2b1b9c0Schristos 		var = (default_offsets);          \
110e2b1b9c0Schristos 		set_offsets(name, var, NULL);     \
111e2b1b9c0Schristos 	}
112e2b1b9c0Schristos 
113e2b1b9c0Schristos /*%
114e2b1b9c0Schristos  * Note:  If additional attributes are added that should not be set for
115e2b1b9c0Schristos  *	  empty names, MAKE_EMPTY() must be changed so it clears them.
116e2b1b9c0Schristos  */
117e2b1b9c0Schristos #define MAKE_EMPTY(name)                                    \
118e2b1b9c0Schristos 	do {                                                \
119e2b1b9c0Schristos 		name->ndata = NULL;                         \
120e2b1b9c0Schristos 		name->length = 0;                           \
121e2b1b9c0Schristos 		name->labels = 0;                           \
122e2b1b9c0Schristos 		name->attributes &= ~DNS_NAMEATTR_ABSOLUTE; \
123245a9365Srillig 	} while (0)
124e2b1b9c0Schristos 
125e2b1b9c0Schristos /*%
126e2b1b9c0Schristos  * A name is "bindable" if it can be set to point to a new value, i.e.
127e2b1b9c0Schristos  * name->ndata and name->length may be changed.
128e2b1b9c0Schristos  */
129e2b1b9c0Schristos #define BINDABLE(name)       \
1309742fdb4Schristos 	((name->attributes & \
1319742fdb4Schristos 	  (DNS_NAMEATTR_READONLY | DNS_NAMEATTR_DYNAMIC)) == 0)
132e2b1b9c0Schristos 
133e2b1b9c0Schristos /*%
134e2b1b9c0Schristos  * Note that the name data must be a char array, not a string
135e2b1b9c0Schristos  * literal, to avoid compiler warnings about discarding
136e2b1b9c0Schristos  * the const attribute of a string.
137e2b1b9c0Schristos  */
138e2b1b9c0Schristos static unsigned char root_ndata[] = { "" };
139e2b1b9c0Schristos static unsigned char root_offsets[] = { 0 };
140e2b1b9c0Schristos 
141e2b1b9c0Schristos static dns_name_t root = DNS_NAME_INITABSOLUTE(root_ndata, root_offsets);
142e2b1b9c0Schristos LIBDNS_EXTERNAL_DATA const dns_name_t *dns_rootname = &root;
143e2b1b9c0Schristos 
144e2b1b9c0Schristos static unsigned char wild_ndata[] = { "\001*" };
145e2b1b9c0Schristos static unsigned char wild_offsets[] = { 0 };
146e2b1b9c0Schristos 
1479742fdb4Schristos static dns_name_t const wild = DNS_NAME_INITNONABSOLUTE(wild_ndata,
1489742fdb4Schristos 							wild_offsets);
149e2b1b9c0Schristos 
150e2b1b9c0Schristos LIBDNS_EXTERNAL_DATA const dns_name_t *dns_wildcardname = &wild;
151e2b1b9c0Schristos 
152e2b1b9c0Schristos /*
153e2b1b9c0Schristos  * dns_name_t to text post-conversion procedure.
154e2b1b9c0Schristos  */
1559742fdb4Schristos ISC_THREAD_LOCAL dns_name_totextfilter_t *totext_filter_proc = NULL;
156e2b1b9c0Schristos 
157e2b1b9c0Schristos static void
158e2b1b9c0Schristos set_offsets(const dns_name_t *name, unsigned char *offsets,
159e2b1b9c0Schristos 	    dns_name_t *set_name);
160e2b1b9c0Schristos 
161e2b1b9c0Schristos void
dns_name_init(dns_name_t * name,unsigned char * offsets)162e2b1b9c0Schristos dns_name_init(dns_name_t *name, unsigned char *offsets) {
163e2b1b9c0Schristos 	/*
164e2b1b9c0Schristos 	 * Initialize 'name'.
165e2b1b9c0Schristos 	 */
166e2b1b9c0Schristos 	DNS_NAME_INIT(name, offsets);
167e2b1b9c0Schristos }
168e2b1b9c0Schristos 
169e2b1b9c0Schristos void
dns_name_reset(dns_name_t * name)170e2b1b9c0Schristos dns_name_reset(dns_name_t *name) {
171e2b1b9c0Schristos 	REQUIRE(VALID_NAME(name));
172e2b1b9c0Schristos 	REQUIRE(BINDABLE(name));
173e2b1b9c0Schristos 
174e2b1b9c0Schristos 	DNS_NAME_RESET(name);
175e2b1b9c0Schristos }
176e2b1b9c0Schristos 
177e2b1b9c0Schristos void
dns_name_invalidate(dns_name_t * name)178e2b1b9c0Schristos dns_name_invalidate(dns_name_t *name) {
179e2b1b9c0Schristos 	/*
180e2b1b9c0Schristos 	 * Make 'name' invalid.
181e2b1b9c0Schristos 	 */
182e2b1b9c0Schristos 
183e2b1b9c0Schristos 	REQUIRE(VALID_NAME(name));
184e2b1b9c0Schristos 
185e2b1b9c0Schristos 	name->magic = 0;
186e2b1b9c0Schristos 	name->ndata = NULL;
187e2b1b9c0Schristos 	name->length = 0;
188e2b1b9c0Schristos 	name->labels = 0;
189e2b1b9c0Schristos 	name->attributes = 0;
190e2b1b9c0Schristos 	name->offsets = NULL;
191e2b1b9c0Schristos 	name->buffer = NULL;
192e2b1b9c0Schristos 	ISC_LINK_INIT(name, link);
193e2b1b9c0Schristos }
194e2b1b9c0Schristos 
195f2e20987Schristos bool
dns_name_isvalid(const dns_name_t * name)196e2b1b9c0Schristos dns_name_isvalid(const dns_name_t *name) {
197e2b1b9c0Schristos 	unsigned char *ndata, *offsets;
198e2b1b9c0Schristos 	unsigned int offset, count, length, nlabels;
199e2b1b9c0Schristos 
2009742fdb4Schristos 	if (!VALID_NAME(name)) {
201f2e20987Schristos 		return (false);
2029742fdb4Schristos 	}
203e2b1b9c0Schristos 
2049742fdb4Schristos 	if (name->length > 255U || name->labels > 127U) {
205f2e20987Schristos 		return (false);
2069742fdb4Schristos 	}
207e2b1b9c0Schristos 
208e2b1b9c0Schristos 	ndata = name->ndata;
209e2b1b9c0Schristos 	length = name->length;
210e2b1b9c0Schristos 	offsets = name->offsets;
211e2b1b9c0Schristos 	offset = 0;
212e2b1b9c0Schristos 	nlabels = 0;
213e2b1b9c0Schristos 
214e2b1b9c0Schristos 	while (offset != length) {
215e2b1b9c0Schristos 		count = *ndata;
2169742fdb4Schristos 		if (count > 63U) {
217f2e20987Schristos 			return (false);
2189742fdb4Schristos 		}
2199742fdb4Schristos 		if (offsets != NULL && offsets[nlabels] != offset) {
220f2e20987Schristos 			return (false);
2219742fdb4Schristos 		}
222e2b1b9c0Schristos 
223e2b1b9c0Schristos 		nlabels++;
224e2b1b9c0Schristos 		offset += count + 1;
225e2b1b9c0Schristos 		ndata += count + 1;
2269742fdb4Schristos 		if (offset > length) {
227f2e20987Schristos 			return (false);
228e2b1b9c0Schristos 		}
229e2b1b9c0Schristos 
2309742fdb4Schristos 		if (count == 0) {
2319742fdb4Schristos 			break;
2329742fdb4Schristos 		}
2339742fdb4Schristos 	}
2349742fdb4Schristos 
2359742fdb4Schristos 	if (nlabels != name->labels || offset != name->length) {
236f2e20987Schristos 		return (false);
2379742fdb4Schristos 	}
238e2b1b9c0Schristos 
239f2e20987Schristos 	return (true);
240e2b1b9c0Schristos }
241e2b1b9c0Schristos 
242e2b1b9c0Schristos void
dns_name_setbuffer(dns_name_t * name,isc_buffer_t * buffer)243e2b1b9c0Schristos dns_name_setbuffer(dns_name_t *name, isc_buffer_t *buffer) {
244e2b1b9c0Schristos 	/*
245e2b1b9c0Schristos 	 * Dedicate a buffer for use with 'name'.
246e2b1b9c0Schristos 	 */
247e2b1b9c0Schristos 
248e2b1b9c0Schristos 	REQUIRE(VALID_NAME(name));
2499742fdb4Schristos 	REQUIRE((buffer != NULL && name->buffer == NULL) || (buffer == NULL));
250e2b1b9c0Schristos 
251e2b1b9c0Schristos 	name->buffer = buffer;
252e2b1b9c0Schristos }
253e2b1b9c0Schristos 
254f2e20987Schristos bool
dns_name_hasbuffer(const dns_name_t * name)255e2b1b9c0Schristos dns_name_hasbuffer(const dns_name_t *name) {
256e2b1b9c0Schristos 	/*
257e2b1b9c0Schristos 	 * Does 'name' have a dedicated buffer?
258e2b1b9c0Schristos 	 */
259e2b1b9c0Schristos 
260e2b1b9c0Schristos 	REQUIRE(VALID_NAME(name));
261e2b1b9c0Schristos 
2629742fdb4Schristos 	if (name->buffer != NULL) {
263f2e20987Schristos 		return (true);
2649742fdb4Schristos 	}
265e2b1b9c0Schristos 
266f2e20987Schristos 	return (false);
267e2b1b9c0Schristos }
268e2b1b9c0Schristos 
269f2e20987Schristos bool
dns_name_isabsolute(const dns_name_t * name)270e2b1b9c0Schristos dns_name_isabsolute(const dns_name_t *name) {
271e2b1b9c0Schristos 	/*
272e2b1b9c0Schristos 	 * Does 'name' end in the root label?
273e2b1b9c0Schristos 	 */
274e2b1b9c0Schristos 
275e2b1b9c0Schristos 	REQUIRE(VALID_NAME(name));
276e2b1b9c0Schristos 
2779742fdb4Schristos 	if ((name->attributes & DNS_NAMEATTR_ABSOLUTE) != 0) {
278f2e20987Schristos 		return (true);
2799742fdb4Schristos 	}
280f2e20987Schristos 	return (false);
281e2b1b9c0Schristos }
282e2b1b9c0Schristos 
283e2b1b9c0Schristos #define hyphenchar(c) ((c) == 0x2d)
284e2b1b9c0Schristos #define asterchar(c)  ((c) == 0x2a)
2859742fdb4Schristos #define alphachar(c) \
2869742fdb4Schristos 	(((c) >= 0x41 && (c) <= 0x5a) || ((c) >= 0x61 && (c) <= 0x7a))
287e2b1b9c0Schristos #define digitchar(c)  ((c) >= 0x30 && (c) <= 0x39)
288e2b1b9c0Schristos #define borderchar(c) (alphachar(c) || digitchar(c))
289e2b1b9c0Schristos #define middlechar(c) (borderchar(c) || hyphenchar(c))
290e2b1b9c0Schristos #define domainchar(c) ((c) > 0x20 && (c) < 0x7f)
291e2b1b9c0Schristos 
292f2e20987Schristos bool
dns_name_ismailbox(const dns_name_t * name)293e2b1b9c0Schristos dns_name_ismailbox(const dns_name_t *name) {
294e2b1b9c0Schristos 	unsigned char *ndata, ch;
295e2b1b9c0Schristos 	unsigned int n;
296f2e20987Schristos 	bool first;
297e2b1b9c0Schristos 
298e2b1b9c0Schristos 	REQUIRE(VALID_NAME(name));
299e2b1b9c0Schristos 	REQUIRE(name->labels > 0);
300e2b1b9c0Schristos 	REQUIRE(name->attributes & DNS_NAMEATTR_ABSOLUTE);
301e2b1b9c0Schristos 
302e2b1b9c0Schristos 	/*
303e2b1b9c0Schristos 	 * Root label.
304e2b1b9c0Schristos 	 */
3059742fdb4Schristos 	if (name->length == 1) {
306f2e20987Schristos 		return (true);
3079742fdb4Schristos 	}
308e2b1b9c0Schristos 
309e2b1b9c0Schristos 	ndata = name->ndata;
310e2b1b9c0Schristos 	n = *ndata++;
311e2b1b9c0Schristos 	INSIST(n <= 63);
312e2b1b9c0Schristos 	while (n--) {
313e2b1b9c0Schristos 		ch = *ndata++;
3149742fdb4Schristos 		if (!domainchar(ch)) {
315f2e20987Schristos 			return (false);
316e2b1b9c0Schristos 		}
3179742fdb4Schristos 	}
318e2b1b9c0Schristos 
3199742fdb4Schristos 	if (ndata == name->ndata + name->length) {
320f2e20987Schristos 		return (false);
3219742fdb4Schristos 	}
322e2b1b9c0Schristos 
323e2b1b9c0Schristos 	/*
3240377c12bSchristos 	 * RFC952/RFC1123 hostname.
325e2b1b9c0Schristos 	 */
326e2b1b9c0Schristos 	while (ndata < (name->ndata + name->length)) {
327e2b1b9c0Schristos 		n = *ndata++;
328e2b1b9c0Schristos 		INSIST(n <= 63);
329f2e20987Schristos 		first = true;
330e2b1b9c0Schristos 		while (n--) {
331e2b1b9c0Schristos 			ch = *ndata++;
332e2b1b9c0Schristos 			if (first || n == 0) {
3339742fdb4Schristos 				if (!borderchar(ch)) {
334f2e20987Schristos 					return (false);
3359742fdb4Schristos 				}
336e2b1b9c0Schristos 			} else {
3379742fdb4Schristos 				if (!middlechar(ch)) {
338f2e20987Schristos 					return (false);
339e2b1b9c0Schristos 				}
3409742fdb4Schristos 			}
341f2e20987Schristos 			first = false;
342e2b1b9c0Schristos 		}
343e2b1b9c0Schristos 	}
344f2e20987Schristos 	return (true);
345e2b1b9c0Schristos }
346e2b1b9c0Schristos 
347f2e20987Schristos bool
dns_name_ishostname(const dns_name_t * name,bool wildcard)348f2e20987Schristos dns_name_ishostname(const dns_name_t *name, bool wildcard) {
349e2b1b9c0Schristos 	unsigned char *ndata, ch;
350e2b1b9c0Schristos 	unsigned int n;
351f2e20987Schristos 	bool first;
352e2b1b9c0Schristos 
353e2b1b9c0Schristos 	REQUIRE(VALID_NAME(name));
354e2b1b9c0Schristos 	REQUIRE(name->labels > 0);
355e2b1b9c0Schristos 	REQUIRE(name->attributes & DNS_NAMEATTR_ABSOLUTE);
356e2b1b9c0Schristos 
357e2b1b9c0Schristos 	/*
358e2b1b9c0Schristos 	 * Root label.
359e2b1b9c0Schristos 	 */
3609742fdb4Schristos 	if (name->length == 1) {
361f2e20987Schristos 		return (true);
3629742fdb4Schristos 	}
363e2b1b9c0Schristos 
364e2b1b9c0Schristos 	/*
365e2b1b9c0Schristos 	 * Skip wildcard if this is a ownername.
366e2b1b9c0Schristos 	 */
367e2b1b9c0Schristos 	ndata = name->ndata;
3689742fdb4Schristos 	if (wildcard && ndata[0] == 1 && ndata[1] == '*') {
369e2b1b9c0Schristos 		ndata += 2;
3709742fdb4Schristos 	}
371e2b1b9c0Schristos 
372e2b1b9c0Schristos 	/*
373e2b1b9c0Schristos 	 * RFC292/RFC1123 hostname.
374e2b1b9c0Schristos 	 */
375e2b1b9c0Schristos 	while (ndata < (name->ndata + name->length)) {
376e2b1b9c0Schristos 		n = *ndata++;
377e2b1b9c0Schristos 		INSIST(n <= 63);
378f2e20987Schristos 		first = true;
379e2b1b9c0Schristos 		while (n--) {
380e2b1b9c0Schristos 			ch = *ndata++;
381e2b1b9c0Schristos 			if (first || n == 0) {
3829742fdb4Schristos 				if (!borderchar(ch)) {
383f2e20987Schristos 					return (false);
3849742fdb4Schristos 				}
385e2b1b9c0Schristos 			} else {
3869742fdb4Schristos 				if (!middlechar(ch)) {
387f2e20987Schristos 					return (false);
388e2b1b9c0Schristos 				}
3899742fdb4Schristos 			}
390f2e20987Schristos 			first = false;
391e2b1b9c0Schristos 		}
392e2b1b9c0Schristos 	}
393f2e20987Schristos 	return (true);
394e2b1b9c0Schristos }
395e2b1b9c0Schristos 
396f2e20987Schristos bool
dns_name_iswildcard(const dns_name_t * name)397e2b1b9c0Schristos dns_name_iswildcard(const dns_name_t *name) {
398e2b1b9c0Schristos 	unsigned char *ndata;
399e2b1b9c0Schristos 
400e2b1b9c0Schristos 	/*
401e2b1b9c0Schristos 	 * Is 'name' a wildcard name?
402e2b1b9c0Schristos 	 */
403e2b1b9c0Schristos 
404e2b1b9c0Schristos 	REQUIRE(VALID_NAME(name));
405e2b1b9c0Schristos 	REQUIRE(name->labels > 0);
406e2b1b9c0Schristos 
407e2b1b9c0Schristos 	if (name->length >= 2) {
408e2b1b9c0Schristos 		ndata = name->ndata;
4099742fdb4Schristos 		if (ndata[0] == 1 && ndata[1] == '*') {
410f2e20987Schristos 			return (true);
411e2b1b9c0Schristos 		}
4129742fdb4Schristos 	}
413e2b1b9c0Schristos 
414f2e20987Schristos 	return (false);
415e2b1b9c0Schristos }
416e2b1b9c0Schristos 
417f2e20987Schristos bool
dns_name_internalwildcard(const dns_name_t * name)418e2b1b9c0Schristos dns_name_internalwildcard(const dns_name_t *name) {
419e2b1b9c0Schristos 	unsigned char *ndata;
420e2b1b9c0Schristos 	unsigned int count;
421e2b1b9c0Schristos 	unsigned int label;
422e2b1b9c0Schristos 
423e2b1b9c0Schristos 	/*
424e2b1b9c0Schristos 	 * Does 'name' contain a internal wildcard?
425e2b1b9c0Schristos 	 */
426e2b1b9c0Schristos 
427e2b1b9c0Schristos 	REQUIRE(VALID_NAME(name));
428e2b1b9c0Schristos 	REQUIRE(name->labels > 0);
429e2b1b9c0Schristos 
430e2b1b9c0Schristos 	/*
431e2b1b9c0Schristos 	 * Skip first label.
432e2b1b9c0Schristos 	 */
433e2b1b9c0Schristos 	ndata = name->ndata;
434e2b1b9c0Schristos 	count = *ndata++;
435e2b1b9c0Schristos 	INSIST(count <= 63);
436e2b1b9c0Schristos 	ndata += count;
437e2b1b9c0Schristos 	label = 1;
438e2b1b9c0Schristos 	/*
439e2b1b9c0Schristos 	 * Check all but the last of the remaining labels.
440e2b1b9c0Schristos 	 */
441e2b1b9c0Schristos 	while (label + 1 < name->labels) {
442e2b1b9c0Schristos 		count = *ndata++;
443e2b1b9c0Schristos 		INSIST(count <= 63);
4449742fdb4Schristos 		if (count == 1 && *ndata == '*') {
445f2e20987Schristos 			return (true);
4469742fdb4Schristos 		}
447e2b1b9c0Schristos 		ndata += count;
448e2b1b9c0Schristos 		label++;
449e2b1b9c0Schristos 	}
450f2e20987Schristos 	return (false);
451e2b1b9c0Schristos }
452e2b1b9c0Schristos 
453e2b1b9c0Schristos unsigned int
dns_name_hash(const dns_name_t * name,bool case_sensitive)454f2e20987Schristos dns_name_hash(const dns_name_t *name, bool case_sensitive) {
455e2b1b9c0Schristos 	unsigned int length;
456e2b1b9c0Schristos 
457e2b1b9c0Schristos 	/*
458e2b1b9c0Schristos 	 * Provide a hash value for 'name'.
459e2b1b9c0Schristos 	 */
460e2b1b9c0Schristos 	REQUIRE(VALID_NAME(name));
461e2b1b9c0Schristos 
4629ad14dd7Schristos 	if (name->labels == 0) {
463e2b1b9c0Schristos 		return (0);
4649ad14dd7Schristos 	}
465e2b1b9c0Schristos 
466e2b1b9c0Schristos 	length = name->length;
4679ad14dd7Schristos 	if (length > 16) {
468e2b1b9c0Schristos 		length = 16;
4699ad14dd7Schristos 	}
470e2b1b9c0Schristos 
47173584a28Schristos 	/* High bits are more random. */
47273584a28Schristos 	return (isc_hash32(name->ndata, length, case_sensitive));
473e2b1b9c0Schristos }
474e2b1b9c0Schristos 
475e2b1b9c0Schristos unsigned int
dns_name_fullhash(const dns_name_t * name,bool case_sensitive)476f2e20987Schristos dns_name_fullhash(const dns_name_t *name, bool case_sensitive) {
477e2b1b9c0Schristos 	/*
478e2b1b9c0Schristos 	 * Provide a hash value for 'name'.
479e2b1b9c0Schristos 	 */
480e2b1b9c0Schristos 	REQUIRE(VALID_NAME(name));
481e2b1b9c0Schristos 
4829ad14dd7Schristos 	if (name->labels == 0) {
483e2b1b9c0Schristos 		return (0);
4849ad14dd7Schristos 	}
485e2b1b9c0Schristos 
48673584a28Schristos 	/* High bits are more random. */
48773584a28Schristos 	return (isc_hash32(name->ndata, name->length, case_sensitive));
488e2b1b9c0Schristos }
489e2b1b9c0Schristos 
490e2b1b9c0Schristos dns_namereln_t
dns_name_fullcompare(const dns_name_t * name1,const dns_name_t * name2,int * orderp,unsigned int * nlabelsp)491e2b1b9c0Schristos dns_name_fullcompare(const dns_name_t *name1, const dns_name_t *name2,
4929742fdb4Schristos 		     int *orderp, unsigned int *nlabelsp) {
493e2b1b9c0Schristos 	unsigned int l1, l2, l, count1, count2, count, nlabels;
494e2b1b9c0Schristos 	int cdiff, ldiff, chdiff;
495e2b1b9c0Schristos 	unsigned char *label1, *label2;
496e2b1b9c0Schristos 	unsigned char *offsets1, *offsets2;
497e2b1b9c0Schristos 	dns_offsets_t odata1, odata2;
498e2b1b9c0Schristos 	dns_namereln_t namereln = dns_namereln_none;
499e2b1b9c0Schristos 
500e2b1b9c0Schristos 	/*
501e2b1b9c0Schristos 	 * Determine the relative ordering under the DNSSEC order relation of
502e2b1b9c0Schristos 	 * 'name1' and 'name2', and also determine the hierarchical
503e2b1b9c0Schristos 	 * relationship of the names.
504e2b1b9c0Schristos 	 *
505e2b1b9c0Schristos 	 * Note: It makes no sense for one of the names to be relative and the
506e2b1b9c0Schristos 	 * other absolute.  If both names are relative, then to be meaningfully
507e2b1b9c0Schristos 	 * compared the caller must ensure that they are both relative to the
508e2b1b9c0Schristos 	 * same domain.
509e2b1b9c0Schristos 	 */
510e2b1b9c0Schristos 
511e2b1b9c0Schristos 	REQUIRE(VALID_NAME(name1));
512e2b1b9c0Schristos 	REQUIRE(VALID_NAME(name2));
513e2b1b9c0Schristos 	REQUIRE(orderp != NULL);
514e2b1b9c0Schristos 	REQUIRE(nlabelsp != NULL);
515e2b1b9c0Schristos 	/*
516e2b1b9c0Schristos 	 * Either name1 is absolute and name2 is absolute, or neither is.
517e2b1b9c0Schristos 	 */
518e2b1b9c0Schristos 	REQUIRE((name1->attributes & DNS_NAMEATTR_ABSOLUTE) ==
519e2b1b9c0Schristos 		(name2->attributes & DNS_NAMEATTR_ABSOLUTE));
520e2b1b9c0Schristos 
521e2b1b9c0Schristos 	if (ISC_UNLIKELY(name1 == name2)) {
522e2b1b9c0Schristos 		*orderp = 0;
523e2b1b9c0Schristos 		*nlabelsp = name1->labels;
524e2b1b9c0Schristos 		return (dns_namereln_equal);
525e2b1b9c0Schristos 	}
526e2b1b9c0Schristos 
527e2b1b9c0Schristos 	SETUP_OFFSETS(name1, offsets1, odata1);
528e2b1b9c0Schristos 	SETUP_OFFSETS(name2, offsets2, odata2);
529e2b1b9c0Schristos 
530e2b1b9c0Schristos 	nlabels = 0;
531e2b1b9c0Schristos 	l1 = name1->labels;
532e2b1b9c0Schristos 	l2 = name2->labels;
533e2b1b9c0Schristos 	if (l2 > l1) {
534e2b1b9c0Schristos 		l = l1;
535e2b1b9c0Schristos 		ldiff = 0 - (l2 - l1);
536e2b1b9c0Schristos 	} else {
537e2b1b9c0Schristos 		l = l2;
538e2b1b9c0Schristos 		ldiff = l1 - l2;
539e2b1b9c0Schristos 	}
540e2b1b9c0Schristos 
541e2b1b9c0Schristos 	offsets1 += l1;
542e2b1b9c0Schristos 	offsets2 += l2;
543e2b1b9c0Schristos 
544e2b1b9c0Schristos 	while (ISC_LIKELY(l > 0)) {
545e2b1b9c0Schristos 		l--;
546e2b1b9c0Schristos 		offsets1--;
547e2b1b9c0Schristos 		offsets2--;
548e2b1b9c0Schristos 		label1 = &name1->ndata[*offsets1];
549e2b1b9c0Schristos 		label2 = &name2->ndata[*offsets2];
550e2b1b9c0Schristos 		count1 = *label1++;
551e2b1b9c0Schristos 		count2 = *label2++;
552e2b1b9c0Schristos 
553e2b1b9c0Schristos 		/*
554e2b1b9c0Schristos 		 * We dropped bitstring labels, and we don't support any
555e2b1b9c0Schristos 		 * other extended label types.
556e2b1b9c0Schristos 		 */
557e2b1b9c0Schristos 		INSIST(count1 <= 63 && count2 <= 63);
558e2b1b9c0Schristos 
559e2b1b9c0Schristos 		cdiff = (int)count1 - (int)count2;
5609742fdb4Schristos 		if (cdiff < 0) {
561e2b1b9c0Schristos 			count = count1;
5629742fdb4Schristos 		} else {
563e2b1b9c0Schristos 			count = count2;
5649742fdb4Schristos 		}
565e2b1b9c0Schristos 
566e2b1b9c0Schristos 		/* Loop unrolled for performance */
567e2b1b9c0Schristos 		while (ISC_LIKELY(count > 3)) {
568e2b1b9c0Schristos 			chdiff = (int)maptolower[label1[0]] -
569e2b1b9c0Schristos 				 (int)maptolower[label2[0]];
570e2b1b9c0Schristos 			if (chdiff != 0) {
571e2b1b9c0Schristos 				*orderp = chdiff;
572e2b1b9c0Schristos 				goto done;
573e2b1b9c0Schristos 			}
574e2b1b9c0Schristos 			chdiff = (int)maptolower[label1[1]] -
575e2b1b9c0Schristos 				 (int)maptolower[label2[1]];
576e2b1b9c0Schristos 			if (chdiff != 0) {
577e2b1b9c0Schristos 				*orderp = chdiff;
578e2b1b9c0Schristos 				goto done;
579e2b1b9c0Schristos 			}
580e2b1b9c0Schristos 			chdiff = (int)maptolower[label1[2]] -
581e2b1b9c0Schristos 				 (int)maptolower[label2[2]];
582e2b1b9c0Schristos 			if (chdiff != 0) {
583e2b1b9c0Schristos 				*orderp = chdiff;
584e2b1b9c0Schristos 				goto done;
585e2b1b9c0Schristos 			}
586e2b1b9c0Schristos 			chdiff = (int)maptolower[label1[3]] -
587e2b1b9c0Schristos 				 (int)maptolower[label2[3]];
588e2b1b9c0Schristos 			if (chdiff != 0) {
589e2b1b9c0Schristos 				*orderp = chdiff;
590e2b1b9c0Schristos 				goto done;
591e2b1b9c0Schristos 			}
592e2b1b9c0Schristos 			count -= 4;
593e2b1b9c0Schristos 			label1 += 4;
594e2b1b9c0Schristos 			label2 += 4;
595e2b1b9c0Schristos 		}
596e2b1b9c0Schristos 		while (ISC_LIKELY(count-- > 0)) {
597e2b1b9c0Schristos 			chdiff = (int)maptolower[*label1++] -
598e2b1b9c0Schristos 				 (int)maptolower[*label2++];
599e2b1b9c0Schristos 			if (chdiff != 0) {
600e2b1b9c0Schristos 				*orderp = chdiff;
601e2b1b9c0Schristos 				goto done;
602e2b1b9c0Schristos 			}
603e2b1b9c0Schristos 		}
604e2b1b9c0Schristos 		if (cdiff != 0) {
605e2b1b9c0Schristos 			*orderp = cdiff;
606e2b1b9c0Schristos 			goto done;
607e2b1b9c0Schristos 		}
608e2b1b9c0Schristos 		nlabels++;
609e2b1b9c0Schristos 	}
610e2b1b9c0Schristos 
611e2b1b9c0Schristos 	*orderp = ldiff;
6129742fdb4Schristos 	if (ldiff < 0) {
613e2b1b9c0Schristos 		namereln = dns_namereln_contains;
6149742fdb4Schristos 	} else if (ldiff > 0) {
615e2b1b9c0Schristos 		namereln = dns_namereln_subdomain;
6169742fdb4Schristos 	} else {
617e2b1b9c0Schristos 		namereln = dns_namereln_equal;
6189742fdb4Schristos 	}
619e2b1b9c0Schristos 	*nlabelsp = nlabels;
620e2b1b9c0Schristos 	return (namereln);
621e2b1b9c0Schristos 
622e2b1b9c0Schristos done:
623e2b1b9c0Schristos 	*nlabelsp = nlabels;
6249742fdb4Schristos 	if (nlabels > 0) {
625e2b1b9c0Schristos 		namereln = dns_namereln_commonancestor;
6269742fdb4Schristos 	}
627e2b1b9c0Schristos 
628e2b1b9c0Schristos 	return (namereln);
629e2b1b9c0Schristos }
630e2b1b9c0Schristos 
631e2b1b9c0Schristos int
dns_name_compare(const dns_name_t * name1,const dns_name_t * name2)632e2b1b9c0Schristos dns_name_compare(const dns_name_t *name1, const dns_name_t *name2) {
633e2b1b9c0Schristos 	int order;
634e2b1b9c0Schristos 	unsigned int nlabels;
635e2b1b9c0Schristos 
636e2b1b9c0Schristos 	/*
637e2b1b9c0Schristos 	 * Determine the relative ordering under the DNSSEC order relation of
638e2b1b9c0Schristos 	 * 'name1' and 'name2'.
639e2b1b9c0Schristos 	 *
640e2b1b9c0Schristos 	 * Note: It makes no sense for one of the names to be relative and the
641e2b1b9c0Schristos 	 * other absolute.  If both names are relative, then to be meaningfully
642e2b1b9c0Schristos 	 * compared the caller must ensure that they are both relative to the
643e2b1b9c0Schristos 	 * same domain.
644e2b1b9c0Schristos 	 */
645e2b1b9c0Schristos 
646e2b1b9c0Schristos 	(void)dns_name_fullcompare(name1, name2, &order, &nlabels);
647e2b1b9c0Schristos 
648e2b1b9c0Schristos 	return (order);
649e2b1b9c0Schristos }
650e2b1b9c0Schristos 
651f2e20987Schristos bool
dns_name_equal(const dns_name_t * name1,const dns_name_t * name2)652e2b1b9c0Schristos dns_name_equal(const dns_name_t *name1, const dns_name_t *name2) {
653e2b1b9c0Schristos 	unsigned int l, count;
654e2b1b9c0Schristos 	unsigned char c;
655e2b1b9c0Schristos 	unsigned char *label1, *label2;
656e2b1b9c0Schristos 
657e2b1b9c0Schristos 	/*
658e2b1b9c0Schristos 	 * Are 'name1' and 'name2' equal?
659e2b1b9c0Schristos 	 *
660e2b1b9c0Schristos 	 * Note: It makes no sense for one of the names to be relative and the
661e2b1b9c0Schristos 	 * other absolute.  If both names are relative, then to be meaningfully
662e2b1b9c0Schristos 	 * compared the caller must ensure that they are both relative to the
663e2b1b9c0Schristos 	 * same domain.
664e2b1b9c0Schristos 	 */
665e2b1b9c0Schristos 
666e2b1b9c0Schristos 	REQUIRE(VALID_NAME(name1));
667e2b1b9c0Schristos 	REQUIRE(VALID_NAME(name2));
668e2b1b9c0Schristos 	/*
669e2b1b9c0Schristos 	 * Either name1 is absolute and name2 is absolute, or neither is.
670e2b1b9c0Schristos 	 */
671e2b1b9c0Schristos 	REQUIRE((name1->attributes & DNS_NAMEATTR_ABSOLUTE) ==
672e2b1b9c0Schristos 		(name2->attributes & DNS_NAMEATTR_ABSOLUTE));
673e2b1b9c0Schristos 
6749742fdb4Schristos 	if (ISC_UNLIKELY(name1 == name2)) {
675f2e20987Schristos 		return (true);
6769742fdb4Schristos 	}
677e2b1b9c0Schristos 
6789742fdb4Schristos 	if (name1->length != name2->length) {
679f2e20987Schristos 		return (false);
6809742fdb4Schristos 	}
681e2b1b9c0Schristos 
682e2b1b9c0Schristos 	l = name1->labels;
683e2b1b9c0Schristos 
6849742fdb4Schristos 	if (l != name2->labels) {
685f2e20987Schristos 		return (false);
6869742fdb4Schristos 	}
687e2b1b9c0Schristos 
688e2b1b9c0Schristos 	label1 = name1->ndata;
689e2b1b9c0Schristos 	label2 = name2->ndata;
690e2b1b9c0Schristos 	while (ISC_LIKELY(l-- > 0)) {
691e2b1b9c0Schristos 		count = *label1++;
6929742fdb4Schristos 		if (count != *label2++) {
693f2e20987Schristos 			return (false);
6949742fdb4Schristos 		}
695e2b1b9c0Schristos 
696e2b1b9c0Schristos 		INSIST(count <= 63); /* no bitstring support */
697e2b1b9c0Schristos 
698e2b1b9c0Schristos 		/* Loop unrolled for performance */
699e2b1b9c0Schristos 		while (ISC_LIKELY(count > 3)) {
700e2b1b9c0Schristos 			c = maptolower[label1[0]];
7019742fdb4Schristos 			if (c != maptolower[label2[0]]) {
702f2e20987Schristos 				return (false);
7039742fdb4Schristos 			}
704e2b1b9c0Schristos 			c = maptolower[label1[1]];
7059742fdb4Schristos 			if (c != maptolower[label2[1]]) {
706f2e20987Schristos 				return (false);
7079742fdb4Schristos 			}
708e2b1b9c0Schristos 			c = maptolower[label1[2]];
7099742fdb4Schristos 			if (c != maptolower[label2[2]]) {
710f2e20987Schristos 				return (false);
7119742fdb4Schristos 			}
712e2b1b9c0Schristos 			c = maptolower[label1[3]];
7139742fdb4Schristos 			if (c != maptolower[label2[3]]) {
714f2e20987Schristos 				return (false);
7159742fdb4Schristos 			}
716e2b1b9c0Schristos 			count -= 4;
717e2b1b9c0Schristos 			label1 += 4;
718e2b1b9c0Schristos 			label2 += 4;
719e2b1b9c0Schristos 		}
720e2b1b9c0Schristos 		while (ISC_LIKELY(count-- > 0)) {
721e2b1b9c0Schristos 			c = maptolower[*label1++];
7229742fdb4Schristos 			if (c != maptolower[*label2++]) {
723f2e20987Schristos 				return (false);
724e2b1b9c0Schristos 			}
725e2b1b9c0Schristos 		}
7269742fdb4Schristos 	}
727e2b1b9c0Schristos 
728f2e20987Schristos 	return (true);
729e2b1b9c0Schristos }
730e2b1b9c0Schristos 
731f2e20987Schristos bool
dns_name_caseequal(const dns_name_t * name1,const dns_name_t * name2)732e2b1b9c0Schristos dns_name_caseequal(const dns_name_t *name1, const dns_name_t *name2) {
733e2b1b9c0Schristos 	/*
734e2b1b9c0Schristos 	 * Are 'name1' and 'name2' equal?
735e2b1b9c0Schristos 	 *
736e2b1b9c0Schristos 	 * Note: It makes no sense for one of the names to be relative and the
737e2b1b9c0Schristos 	 * other absolute.  If both names are relative, then to be meaningfully
738e2b1b9c0Schristos 	 * compared the caller must ensure that they are both relative to the
739e2b1b9c0Schristos 	 * same domain.
740e2b1b9c0Schristos 	 */
741e2b1b9c0Schristos 
742e2b1b9c0Schristos 	REQUIRE(VALID_NAME(name1));
743e2b1b9c0Schristos 	REQUIRE(VALID_NAME(name2));
744e2b1b9c0Schristos 	/*
745e2b1b9c0Schristos 	 * Either name1 is absolute and name2 is absolute, or neither is.
746e2b1b9c0Schristos 	 */
747e2b1b9c0Schristos 	REQUIRE((name1->attributes & DNS_NAMEATTR_ABSOLUTE) ==
748e2b1b9c0Schristos 		(name2->attributes & DNS_NAMEATTR_ABSOLUTE));
749e2b1b9c0Schristos 
7509742fdb4Schristos 	if (name1->length != name2->length) {
751f2e20987Schristos 		return (false);
7529742fdb4Schristos 	}
753e2b1b9c0Schristos 
7549742fdb4Schristos 	if (memcmp(name1->ndata, name2->ndata, name1->length) != 0) {
755f2e20987Schristos 		return (false);
7569742fdb4Schristos 	}
757e2b1b9c0Schristos 
758f2e20987Schristos 	return (true);
759e2b1b9c0Schristos }
760e2b1b9c0Schristos 
761e2b1b9c0Schristos int
dns_name_rdatacompare(const dns_name_t * name1,const dns_name_t * name2)762e2b1b9c0Schristos dns_name_rdatacompare(const dns_name_t *name1, const dns_name_t *name2) {
763e2b1b9c0Schristos 	unsigned int l1, l2, l, count1, count2, count;
764e2b1b9c0Schristos 	unsigned char c1, c2;
765e2b1b9c0Schristos 	unsigned char *label1, *label2;
766e2b1b9c0Schristos 
767e2b1b9c0Schristos 	/*
768e2b1b9c0Schristos 	 * Compare two absolute names as rdata.
769e2b1b9c0Schristos 	 */
770e2b1b9c0Schristos 
771e2b1b9c0Schristos 	REQUIRE(VALID_NAME(name1));
772e2b1b9c0Schristos 	REQUIRE(name1->labels > 0);
773e2b1b9c0Schristos 	REQUIRE((name1->attributes & DNS_NAMEATTR_ABSOLUTE) != 0);
774e2b1b9c0Schristos 	REQUIRE(VALID_NAME(name2));
775e2b1b9c0Schristos 	REQUIRE(name2->labels > 0);
776e2b1b9c0Schristos 	REQUIRE((name2->attributes & DNS_NAMEATTR_ABSOLUTE) != 0);
777e2b1b9c0Schristos 
778e2b1b9c0Schristos 	l1 = name1->labels;
779e2b1b9c0Schristos 	l2 = name2->labels;
780e2b1b9c0Schristos 
781e2b1b9c0Schristos 	l = (l1 < l2) ? l1 : l2;
782e2b1b9c0Schristos 
783e2b1b9c0Schristos 	label1 = name1->ndata;
784e2b1b9c0Schristos 	label2 = name2->ndata;
785e2b1b9c0Schristos 	while (l > 0) {
786e2b1b9c0Schristos 		l--;
787e2b1b9c0Schristos 		count1 = *label1++;
788e2b1b9c0Schristos 		count2 = *label2++;
789e2b1b9c0Schristos 
790e2b1b9c0Schristos 		/* no bitstring support */
791e2b1b9c0Schristos 		INSIST(count1 <= 63 && count2 <= 63);
792e2b1b9c0Schristos 
7939742fdb4Schristos 		if (count1 != count2) {
794e2b1b9c0Schristos 			return ((count1 < count2) ? -1 : 1);
7959742fdb4Schristos 		}
796e2b1b9c0Schristos 		count = count1;
797e2b1b9c0Schristos 		while (count > 0) {
798e2b1b9c0Schristos 			count--;
799e2b1b9c0Schristos 			c1 = maptolower[*label1++];
800e2b1b9c0Schristos 			c2 = maptolower[*label2++];
8019742fdb4Schristos 			if (c1 < c2) {
802e2b1b9c0Schristos 				return (-1);
8039742fdb4Schristos 			} else if (c1 > c2) {
804e2b1b9c0Schristos 				return (1);
805e2b1b9c0Schristos 			}
806e2b1b9c0Schristos 		}
8079742fdb4Schristos 	}
808e2b1b9c0Schristos 
809e2b1b9c0Schristos 	/*
810e2b1b9c0Schristos 	 * If one name had more labels than the other, their common
811e2b1b9c0Schristos 	 * prefix must have been different because the shorter name
812e2b1b9c0Schristos 	 * ended with the root label and the longer one can't have
813e2b1b9c0Schristos 	 * a root label in the middle of it.  Therefore, if we get
814e2b1b9c0Schristos 	 * to this point, the lengths must be equal.
815e2b1b9c0Schristos 	 */
816e2b1b9c0Schristos 	INSIST(l1 == l2);
817e2b1b9c0Schristos 
818e2b1b9c0Schristos 	return (0);
819e2b1b9c0Schristos }
820e2b1b9c0Schristos 
821f2e20987Schristos bool
dns_name_issubdomain(const dns_name_t * name1,const dns_name_t * name2)822e2b1b9c0Schristos dns_name_issubdomain(const dns_name_t *name1, const dns_name_t *name2) {
823e2b1b9c0Schristos 	int order;
824e2b1b9c0Schristos 	unsigned int nlabels;
825e2b1b9c0Schristos 	dns_namereln_t namereln;
826e2b1b9c0Schristos 
827e2b1b9c0Schristos 	/*
828e2b1b9c0Schristos 	 * Is 'name1' a subdomain of 'name2'?
829e2b1b9c0Schristos 	 *
830e2b1b9c0Schristos 	 * Note: It makes no sense for one of the names to be relative and the
831e2b1b9c0Schristos 	 * other absolute.  If both names are relative, then to be meaningfully
832e2b1b9c0Schristos 	 * compared the caller must ensure that they are both relative to the
833e2b1b9c0Schristos 	 * same domain.
834e2b1b9c0Schristos 	 */
835e2b1b9c0Schristos 
836e2b1b9c0Schristos 	namereln = dns_name_fullcompare(name1, name2, &order, &nlabels);
837e2b1b9c0Schristos 	if (namereln == dns_namereln_subdomain ||
838*4ac1c27eSchristos 	    namereln == dns_namereln_equal)
839*4ac1c27eSchristos 	{
840f2e20987Schristos 		return (true);
8419742fdb4Schristos 	}
842e2b1b9c0Schristos 
843f2e20987Schristos 	return (false);
844e2b1b9c0Schristos }
845e2b1b9c0Schristos 
846f2e20987Schristos bool
dns_name_matcheswildcard(const dns_name_t * name,const dns_name_t * wname)847e2b1b9c0Schristos dns_name_matcheswildcard(const dns_name_t *name, const dns_name_t *wname) {
848e2b1b9c0Schristos 	int order;
849e2b1b9c0Schristos 	unsigned int nlabels, labels;
850e2b1b9c0Schristos 	dns_name_t tname;
851e2b1b9c0Schristos 
852e2b1b9c0Schristos 	REQUIRE(VALID_NAME(name));
853e2b1b9c0Schristos 	REQUIRE(name->labels > 0);
854e2b1b9c0Schristos 	REQUIRE(VALID_NAME(wname));
855e2b1b9c0Schristos 	labels = wname->labels;
856e2b1b9c0Schristos 	REQUIRE(labels > 0);
857e2b1b9c0Schristos 	REQUIRE(dns_name_iswildcard(wname));
858e2b1b9c0Schristos 
859e2b1b9c0Schristos 	DNS_NAME_INIT(&tname, NULL);
860e2b1b9c0Schristos 	dns_name_getlabelsequence(wname, 1, labels - 1, &tname);
861e2b1b9c0Schristos 	if (dns_name_fullcompare(name, &tname, &order, &nlabels) ==
862e2b1b9c0Schristos 	    dns_namereln_subdomain)
8639742fdb4Schristos 	{
864f2e20987Schristos 		return (true);
8659742fdb4Schristos 	}
866f2e20987Schristos 	return (false);
867e2b1b9c0Schristos }
868e2b1b9c0Schristos 
869e2b1b9c0Schristos unsigned int
dns_name_countlabels(const dns_name_t * name)870e2b1b9c0Schristos dns_name_countlabels(const dns_name_t *name) {
871e2b1b9c0Schristos 	/*
872e2b1b9c0Schristos 	 * How many labels does 'name' have?
873e2b1b9c0Schristos 	 */
874e2b1b9c0Schristos 
875e2b1b9c0Schristos 	REQUIRE(VALID_NAME(name));
876e2b1b9c0Schristos 
877e2b1b9c0Schristos 	ENSURE(name->labels <= 128);
878e2b1b9c0Schristos 
879e2b1b9c0Schristos 	return (name->labels);
880e2b1b9c0Schristos }
881e2b1b9c0Schristos 
882e2b1b9c0Schristos void
dns_name_getlabel(const dns_name_t * name,unsigned int n,dns_label_t * label)883e2b1b9c0Schristos dns_name_getlabel(const dns_name_t *name, unsigned int n, dns_label_t *label) {
884e2b1b9c0Schristos 	unsigned char *offsets;
885e2b1b9c0Schristos 	dns_offsets_t odata;
886e2b1b9c0Schristos 
887e2b1b9c0Schristos 	/*
888e2b1b9c0Schristos 	 * Make 'label' refer to the 'n'th least significant label of 'name'.
889e2b1b9c0Schristos 	 */
890e2b1b9c0Schristos 
891e2b1b9c0Schristos 	REQUIRE(VALID_NAME(name));
892e2b1b9c0Schristos 	REQUIRE(name->labels > 0);
893e2b1b9c0Schristos 	REQUIRE(n < name->labels);
894e2b1b9c0Schristos 	REQUIRE(label != NULL);
895e2b1b9c0Schristos 
896e2b1b9c0Schristos 	SETUP_OFFSETS(name, offsets, odata);
897e2b1b9c0Schristos 
898e2b1b9c0Schristos 	label->base = &name->ndata[offsets[n]];
8999742fdb4Schristos 	if (n == name->labels - 1) {
900e2b1b9c0Schristos 		label->length = name->length - offsets[n];
9019742fdb4Schristos 	} else {
902e2b1b9c0Schristos 		label->length = offsets[n + 1] - offsets[n];
903e2b1b9c0Schristos 	}
9049742fdb4Schristos }
905e2b1b9c0Schristos 
906e2b1b9c0Schristos void
dns_name_getlabelsequence(const dns_name_t * source,unsigned int first,unsigned int n,dns_name_t * target)9079742fdb4Schristos dns_name_getlabelsequence(const dns_name_t *source, unsigned int first,
9089742fdb4Schristos 			  unsigned int n, dns_name_t *target) {
909e2b1b9c0Schristos 	unsigned char *p, l;
910e2b1b9c0Schristos 	unsigned int firstoffset, endoffset;
911e2b1b9c0Schristos 	unsigned int i;
912e2b1b9c0Schristos 
913e2b1b9c0Schristos 	/*
914e2b1b9c0Schristos 	 * Make 'target' refer to the 'n' labels including and following
915e2b1b9c0Schristos 	 * 'first' in 'source'.
916e2b1b9c0Schristos 	 */
917e2b1b9c0Schristos 
918e2b1b9c0Schristos 	REQUIRE(VALID_NAME(source));
919e2b1b9c0Schristos 	REQUIRE(VALID_NAME(target));
920e2b1b9c0Schristos 	REQUIRE(first <= source->labels);
921e2b1b9c0Schristos 	REQUIRE(n <= source->labels - first); /* note first+n could overflow */
922e2b1b9c0Schristos 	REQUIRE(BINDABLE(target));
923e2b1b9c0Schristos 
924e2b1b9c0Schristos 	p = source->ndata;
925e2b1b9c0Schristos 	if (ISC_UNLIKELY(first == source->labels)) {
926e2b1b9c0Schristos 		firstoffset = source->length;
927e2b1b9c0Schristos 	} else {
928e2b1b9c0Schristos 		for (i = 0; i < first; i++) {
929e2b1b9c0Schristos 			l = *p;
930e2b1b9c0Schristos 			p += l + 1;
931e2b1b9c0Schristos 		}
932e2b1b9c0Schristos 		firstoffset = (unsigned int)(p - source->ndata);
933e2b1b9c0Schristos 	}
934e2b1b9c0Schristos 
9359742fdb4Schristos 	if (ISC_LIKELY(first + n == source->labels)) {
936e2b1b9c0Schristos 		endoffset = source->length;
9379742fdb4Schristos 	} else {
938e2b1b9c0Schristos 		for (i = 0; i < n; i++) {
939e2b1b9c0Schristos 			l = *p;
940e2b1b9c0Schristos 			p += l + 1;
941e2b1b9c0Schristos 		}
942e2b1b9c0Schristos 		endoffset = (unsigned int)(p - source->ndata);
943e2b1b9c0Schristos 	}
944e2b1b9c0Schristos 
945e2b1b9c0Schristos 	target->ndata = &source->ndata[firstoffset];
946e2b1b9c0Schristos 	target->length = endoffset - firstoffset;
947e2b1b9c0Schristos 
948e2b1b9c0Schristos 	if (first + n == source->labels && n > 0 &&
949e2b1b9c0Schristos 	    (source->attributes & DNS_NAMEATTR_ABSOLUTE) != 0)
9509742fdb4Schristos 	{
951e2b1b9c0Schristos 		target->attributes |= DNS_NAMEATTR_ABSOLUTE;
9529742fdb4Schristos 	} else {
953e2b1b9c0Schristos 		target->attributes &= ~DNS_NAMEATTR_ABSOLUTE;
9549742fdb4Schristos 	}
955e2b1b9c0Schristos 
956e2b1b9c0Schristos 	target->labels = n;
957e2b1b9c0Schristos 
958e2b1b9c0Schristos 	/*
959e2b1b9c0Schristos 	 * If source and target are the same, and we're making target
960e2b1b9c0Schristos 	 * a prefix of source, the offsets table is correct already
961e2b1b9c0Schristos 	 * so we don't need to call set_offsets().
962e2b1b9c0Schristos 	 */
9639742fdb4Schristos 	if (target->offsets != NULL && (target != source || first != 0)) {
964e2b1b9c0Schristos 		set_offsets(target, target->offsets, NULL);
965e2b1b9c0Schristos 	}
9669742fdb4Schristos }
967e2b1b9c0Schristos 
968e2b1b9c0Schristos void
dns_name_clone(const dns_name_t * source,dns_name_t * target)969e2b1b9c0Schristos dns_name_clone(const dns_name_t *source, dns_name_t *target) {
970e2b1b9c0Schristos 	/*
971e2b1b9c0Schristos 	 * Make 'target' refer to the same name as 'source'.
972e2b1b9c0Schristos 	 */
973e2b1b9c0Schristos 
974e2b1b9c0Schristos 	REQUIRE(VALID_NAME(source));
975e2b1b9c0Schristos 	REQUIRE(VALID_NAME(target));
976e2b1b9c0Schristos 	REQUIRE(BINDABLE(target));
977e2b1b9c0Schristos 
978e2b1b9c0Schristos 	target->ndata = source->ndata;
979e2b1b9c0Schristos 	target->length = source->length;
980e2b1b9c0Schristos 	target->labels = source->labels;
981e2b1b9c0Schristos 	target->attributes = source->attributes &
9829742fdb4Schristos 			     (unsigned int)~(DNS_NAMEATTR_READONLY |
9839742fdb4Schristos 					     DNS_NAMEATTR_DYNAMIC |
984e2b1b9c0Schristos 					     DNS_NAMEATTR_DYNOFFSETS);
985e2b1b9c0Schristos 	if (target->offsets != NULL && source->labels > 0) {
9869742fdb4Schristos 		if (source->offsets != NULL) {
987e2b1b9c0Schristos 			memmove(target->offsets, source->offsets,
988e2b1b9c0Schristos 				source->labels);
9899742fdb4Schristos 		} else {
990e2b1b9c0Schristos 			set_offsets(target, target->offsets, NULL);
991e2b1b9c0Schristos 		}
992e2b1b9c0Schristos 	}
9939742fdb4Schristos }
994e2b1b9c0Schristos 
995e2b1b9c0Schristos void
dns_name_fromregion(dns_name_t * name,const isc_region_t * r)996e2b1b9c0Schristos dns_name_fromregion(dns_name_t *name, const isc_region_t *r) {
997e2b1b9c0Schristos 	unsigned char *offsets;
998e2b1b9c0Schristos 	dns_offsets_t odata;
999e2b1b9c0Schristos 	unsigned int len;
1000e2b1b9c0Schristos 	isc_region_t r2;
1001e2b1b9c0Schristos 
1002e2b1b9c0Schristos 	/*
1003e2b1b9c0Schristos 	 * Make 'name' refer to region 'r'.
1004e2b1b9c0Schristos 	 */
1005e2b1b9c0Schristos 
1006e2b1b9c0Schristos 	REQUIRE(VALID_NAME(name));
1007e2b1b9c0Schristos 	REQUIRE(r != NULL);
1008e2b1b9c0Schristos 	REQUIRE(BINDABLE(name));
1009e2b1b9c0Schristos 
1010e2b1b9c0Schristos 	INIT_OFFSETS(name, offsets, odata);
1011e2b1b9c0Schristos 
1012e2b1b9c0Schristos 	if (name->buffer != NULL) {
1013e2b1b9c0Schristos 		isc_buffer_clear(name->buffer);
1014e2b1b9c0Schristos 		isc_buffer_availableregion(name->buffer, &r2);
1015e2b1b9c0Schristos 		len = (r->length < r2.length) ? r->length : r2.length;
10169742fdb4Schristos 		if (len > DNS_NAME_MAXWIRE) {
1017e2b1b9c0Schristos 			len = DNS_NAME_MAXWIRE;
10189742fdb4Schristos 		}
10199742fdb4Schristos 		if (len != 0) {
1020e2b1b9c0Schristos 			memmove(r2.base, r->base, len);
10219742fdb4Schristos 		}
1022e2b1b9c0Schristos 		name->ndata = r2.base;
1023e2b1b9c0Schristos 		name->length = len;
1024e2b1b9c0Schristos 	} else {
1025e2b1b9c0Schristos 		name->ndata = r->base;
10269742fdb4Schristos 		name->length = (r->length <= DNS_NAME_MAXWIRE)
10279742fdb4Schristos 				       ? r->length
10289742fdb4Schristos 				       : DNS_NAME_MAXWIRE;
1029e2b1b9c0Schristos 	}
1030e2b1b9c0Schristos 
10319742fdb4Schristos 	if (r->length > 0) {
1032e2b1b9c0Schristos 		set_offsets(name, offsets, name);
10339742fdb4Schristos 	} else {
1034e2b1b9c0Schristos 		name->labels = 0;
1035e2b1b9c0Schristos 		name->attributes &= ~DNS_NAMEATTR_ABSOLUTE;
1036e2b1b9c0Schristos 	}
1037e2b1b9c0Schristos 
10389742fdb4Schristos 	if (name->buffer != NULL) {
1039e2b1b9c0Schristos 		isc_buffer_add(name->buffer, name->length);
1040e2b1b9c0Schristos 	}
10419742fdb4Schristos }
1042e2b1b9c0Schristos 
1043e2b1b9c0Schristos void
dns_name_toregion(const dns_name_t * name,isc_region_t * r)1044e2b1b9c0Schristos dns_name_toregion(const dns_name_t *name, isc_region_t *r) {
1045e2b1b9c0Schristos 	/*
1046e2b1b9c0Schristos 	 * Make 'r' refer to 'name'.
1047e2b1b9c0Schristos 	 */
1048e2b1b9c0Schristos 
1049e2b1b9c0Schristos 	REQUIRE(VALID_NAME(name));
1050e2b1b9c0Schristos 	REQUIRE(r != NULL);
1051e2b1b9c0Schristos 
1052e2b1b9c0Schristos 	DNS_NAME_TOREGION(name, r);
1053e2b1b9c0Schristos }
1054e2b1b9c0Schristos 
1055e2b1b9c0Schristos isc_result_t
dns_name_fromtext(dns_name_t * name,isc_buffer_t * source,const dns_name_t * origin,unsigned int options,isc_buffer_t * target)1056e2b1b9c0Schristos dns_name_fromtext(dns_name_t *name, isc_buffer_t *source,
1057e2b1b9c0Schristos 		  const dns_name_t *origin, unsigned int options,
10589742fdb4Schristos 		  isc_buffer_t *target) {
1059e2b1b9c0Schristos 	unsigned char *ndata, *label = NULL;
1060e2b1b9c0Schristos 	char *tdata;
1061e2b1b9c0Schristos 	char c;
1062e2b1b9c0Schristos 	ft_state state;
1063e2b1b9c0Schristos 	unsigned int value = 0, count = 0;
1064e2b1b9c0Schristos 	unsigned int n1 = 0, n2 = 0;
1065e2b1b9c0Schristos 	unsigned int tlen, nrem, nused, digits = 0, labels, tused;
1066f2e20987Schristos 	bool done;
1067e2b1b9c0Schristos 	unsigned char *offsets;
1068e2b1b9c0Schristos 	dns_offsets_t odata;
1069f2e20987Schristos 	bool downcase;
1070e2b1b9c0Schristos 
1071e2b1b9c0Schristos 	/*
1072e2b1b9c0Schristos 	 * Convert the textual representation of a DNS name at source
1073e2b1b9c0Schristos 	 * into uncompressed wire form stored in target.
1074e2b1b9c0Schristos 	 *
1075e2b1b9c0Schristos 	 * Notes:
1076e2b1b9c0Schristos 	 *	Relative domain names will have 'origin' appended to them
1077e2b1b9c0Schristos 	 *	unless 'origin' is NULL, in which case relative domain names
1078e2b1b9c0Schristos 	 *	will remain relative.
1079e2b1b9c0Schristos 	 */
1080e2b1b9c0Schristos 
1081e2b1b9c0Schristos 	REQUIRE(VALID_NAME(name));
1082e2b1b9c0Schristos 	REQUIRE(ISC_BUFFER_VALID(source));
1083e2b1b9c0Schristos 	REQUIRE((target != NULL && ISC_BUFFER_VALID(target)) ||
1084e2b1b9c0Schristos 		(target == NULL && ISC_BUFFER_VALID(name->buffer)));
1085e2b1b9c0Schristos 
1086f2e20987Schristos 	downcase = ((options & DNS_NAME_DOWNCASE) != 0);
1087e2b1b9c0Schristos 
1088e2b1b9c0Schristos 	if (target == NULL && name->buffer != NULL) {
1089e2b1b9c0Schristos 		target = name->buffer;
1090e2b1b9c0Schristos 		isc_buffer_clear(target);
1091e2b1b9c0Schristos 	}
1092e2b1b9c0Schristos 
1093e2b1b9c0Schristos 	REQUIRE(BINDABLE(name));
1094e2b1b9c0Schristos 
1095e2b1b9c0Schristos 	INIT_OFFSETS(name, offsets, odata);
1096e2b1b9c0Schristos 	offsets[0] = 0;
1097e2b1b9c0Schristos 
1098e2b1b9c0Schristos 	/*
1099e2b1b9c0Schristos 	 * Make 'name' empty in case of failure.
1100e2b1b9c0Schristos 	 */
1101e2b1b9c0Schristos 	MAKE_EMPTY(name);
1102e2b1b9c0Schristos 
1103e2b1b9c0Schristos 	/*
1104e2b1b9c0Schristos 	 * Set up the state machine.
1105e2b1b9c0Schristos 	 */
1106e2b1b9c0Schristos 	tdata = (char *)source->base + source->current;
1107e2b1b9c0Schristos 	tlen = isc_buffer_remaininglength(source);
1108e2b1b9c0Schristos 	tused = 0;
1109e2b1b9c0Schristos 	ndata = isc_buffer_used(target);
1110e2b1b9c0Schristos 	nrem = isc_buffer_availablelength(target);
11119742fdb4Schristos 	if (nrem > 255) {
1112e2b1b9c0Schristos 		nrem = 255;
11139742fdb4Schristos 	}
1114e2b1b9c0Schristos 	nused = 0;
1115e2b1b9c0Schristos 	labels = 0;
1116f2e20987Schristos 	done = false;
1117e2b1b9c0Schristos 	state = ft_init;
1118e2b1b9c0Schristos 
1119e2b1b9c0Schristos 	while (nrem > 0 && tlen > 0 && !done) {
1120e2b1b9c0Schristos 		c = *tdata++;
1121e2b1b9c0Schristos 		tlen--;
1122e2b1b9c0Schristos 		tused++;
1123e2b1b9c0Schristos 
1124e2b1b9c0Schristos 		switch (state) {
1125e2b1b9c0Schristos 		case ft_init:
1126e2b1b9c0Schristos 			/*
1127e2b1b9c0Schristos 			 * Is this the root name?
1128e2b1b9c0Schristos 			 */
1129e2b1b9c0Schristos 			if (c == '.') {
11309742fdb4Schristos 				if (tlen != 0) {
1131e2b1b9c0Schristos 					return (DNS_R_EMPTYLABEL);
11329742fdb4Schristos 				}
1133e2b1b9c0Schristos 				labels++;
1134e2b1b9c0Schristos 				*ndata++ = 0;
1135e2b1b9c0Schristos 				nrem--;
1136e2b1b9c0Schristos 				nused++;
1137f2e20987Schristos 				done = true;
1138e2b1b9c0Schristos 				break;
1139e2b1b9c0Schristos 			}
1140e2b1b9c0Schristos 			if (c == '@' && tlen == 0) {
1141e2b1b9c0Schristos 				state = ft_at;
1142e2b1b9c0Schristos 				break;
1143e2b1b9c0Schristos 			}
1144e2b1b9c0Schristos 
1145c0b5d9fbSchristos 			FALLTHROUGH;
1146e2b1b9c0Schristos 		case ft_start:
1147e2b1b9c0Schristos 			label = ndata;
1148e2b1b9c0Schristos 			ndata++;
1149e2b1b9c0Schristos 			nrem--;
1150e2b1b9c0Schristos 			nused++;
1151e2b1b9c0Schristos 			count = 0;
1152e2b1b9c0Schristos 			if (c == '\\') {
1153e2b1b9c0Schristos 				state = ft_initialescape;
1154e2b1b9c0Schristos 				break;
1155e2b1b9c0Schristos 			}
1156e2b1b9c0Schristos 			state = ft_ordinary;
11579742fdb4Schristos 			if (nrem == 0) {
1158e2b1b9c0Schristos 				return (ISC_R_NOSPACE);
11599742fdb4Schristos 			}
1160c0b5d9fbSchristos 			FALLTHROUGH;
1161e2b1b9c0Schristos 		case ft_ordinary:
1162e2b1b9c0Schristos 			if (c == '.') {
11639742fdb4Schristos 				if (count == 0) {
1164e2b1b9c0Schristos 					return (DNS_R_EMPTYLABEL);
11659742fdb4Schristos 				}
1166e2b1b9c0Schristos 				*label = count;
1167e2b1b9c0Schristos 				labels++;
1168e2b1b9c0Schristos 				INSIST(labels <= 127);
1169e2b1b9c0Schristos 				offsets[labels] = nused;
1170e2b1b9c0Schristos 				if (tlen == 0) {
1171e2b1b9c0Schristos 					labels++;
1172e2b1b9c0Schristos 					*ndata++ = 0;
1173e2b1b9c0Schristos 					nrem--;
1174e2b1b9c0Schristos 					nused++;
1175f2e20987Schristos 					done = true;
1176e2b1b9c0Schristos 				}
1177e2b1b9c0Schristos 				state = ft_start;
1178e2b1b9c0Schristos 			} else if (c == '\\') {
1179e2b1b9c0Schristos 				state = ft_escape;
1180e2b1b9c0Schristos 			} else {
11819742fdb4Schristos 				if (count >= 63) {
1182e2b1b9c0Schristos 					return (DNS_R_LABELTOOLONG);
11839742fdb4Schristos 				}
1184e2b1b9c0Schristos 				count++;
1185e2b1b9c0Schristos 				CONVERTTOASCII(c);
11869742fdb4Schristos 				if (downcase) {
1187e2b1b9c0Schristos 					c = maptolower[c & 0xff];
11889742fdb4Schristos 				}
1189e2b1b9c0Schristos 				*ndata++ = c;
1190e2b1b9c0Schristos 				nrem--;
1191e2b1b9c0Schristos 				nused++;
1192e2b1b9c0Schristos 			}
1193e2b1b9c0Schristos 			break;
1194e2b1b9c0Schristos 		case ft_initialescape:
1195e2b1b9c0Schristos 			if (c == '[') {
1196e2b1b9c0Schristos 				/*
1197e2b1b9c0Schristos 				 * This looks like a bitstring label, which
1198e2b1b9c0Schristos 				 * was deprecated.  Intentionally drop it.
1199e2b1b9c0Schristos 				 */
1200e2b1b9c0Schristos 				return (DNS_R_BADLABELTYPE);
1201e2b1b9c0Schristos 			}
1202e2b1b9c0Schristos 			state = ft_escape;
1203e2b1b9c0Schristos 			POST(state);
1204c0b5d9fbSchristos 			FALLTHROUGH;
1205e2b1b9c0Schristos 		case ft_escape:
1206fadf0758Schristos 			if (!isdigit((unsigned char)c)) {
12079742fdb4Schristos 				if (count >= 63) {
1208e2b1b9c0Schristos 					return (DNS_R_LABELTOOLONG);
12099742fdb4Schristos 				}
1210e2b1b9c0Schristos 				count++;
1211e2b1b9c0Schristos 				CONVERTTOASCII(c);
12129742fdb4Schristos 				if (downcase) {
1213e2b1b9c0Schristos 					c = maptolower[c & 0xff];
12149742fdb4Schristos 				}
1215e2b1b9c0Schristos 				*ndata++ = c;
1216e2b1b9c0Schristos 				nrem--;
1217e2b1b9c0Schristos 				nused++;
1218e2b1b9c0Schristos 				state = ft_ordinary;
1219e2b1b9c0Schristos 				break;
1220e2b1b9c0Schristos 			}
1221e2b1b9c0Schristos 			digits = 0;
1222e2b1b9c0Schristos 			value = 0;
1223e2b1b9c0Schristos 			state = ft_escdecimal;
1224c0b5d9fbSchristos 			FALLTHROUGH;
1225e2b1b9c0Schristos 		case ft_escdecimal:
1226fadf0758Schristos 			if (!isdigit((unsigned char)c)) {
1227e2b1b9c0Schristos 				return (DNS_R_BADESCAPE);
12289742fdb4Schristos 			}
1229e2b1b9c0Schristos 			value *= 10;
1230e2b1b9c0Schristos 			value += digitvalue[c & 0xff];
1231e2b1b9c0Schristos 			digits++;
1232e2b1b9c0Schristos 			if (digits == 3) {
12339742fdb4Schristos 				if (value > 255) {
1234e2b1b9c0Schristos 					return (DNS_R_BADESCAPE);
12359742fdb4Schristos 				}
12369742fdb4Schristos 				if (count >= 63) {
1237e2b1b9c0Schristos 					return (DNS_R_LABELTOOLONG);
12389742fdb4Schristos 				}
1239e2b1b9c0Schristos 				count++;
12409742fdb4Schristos 				if (downcase) {
1241e2b1b9c0Schristos 					value = maptolower[value];
12429742fdb4Schristos 				}
1243e2b1b9c0Schristos 				*ndata++ = value;
1244e2b1b9c0Schristos 				nrem--;
1245e2b1b9c0Schristos 				nused++;
1246e2b1b9c0Schristos 				state = ft_ordinary;
1247e2b1b9c0Schristos 			}
1248e2b1b9c0Schristos 			break;
1249e2b1b9c0Schristos 		default:
12509742fdb4Schristos 			FATAL_ERROR(__FILE__, __LINE__, "Unexpected state %d",
12519742fdb4Schristos 				    state);
1252e2b1b9c0Schristos 			/* Does not return. */
1253e2b1b9c0Schristos 		}
1254e2b1b9c0Schristos 	}
1255e2b1b9c0Schristos 
1256e2b1b9c0Schristos 	if (!done) {
12579742fdb4Schristos 		if (nrem == 0) {
1258e2b1b9c0Schristos 			return (ISC_R_NOSPACE);
12599742fdb4Schristos 		}
1260e2b1b9c0Schristos 		INSIST(tlen == 0);
12619742fdb4Schristos 		if (state != ft_ordinary && state != ft_at) {
1262e2b1b9c0Schristos 			return (ISC_R_UNEXPECTEDEND);
12639742fdb4Schristos 		}
1264e2b1b9c0Schristos 		if (state == ft_ordinary) {
1265e2b1b9c0Schristos 			INSIST(count != 0);
1266fadf0758Schristos 			INSIST(label != NULL);
1267e2b1b9c0Schristos 			*label = count;
1268e2b1b9c0Schristos 			labels++;
1269e2b1b9c0Schristos 			INSIST(labels <= 127);
1270e2b1b9c0Schristos 			offsets[labels] = nused;
1271e2b1b9c0Schristos 		}
1272e2b1b9c0Schristos 		if (origin != NULL) {
12739742fdb4Schristos 			if (nrem < origin->length) {
1274e2b1b9c0Schristos 				return (ISC_R_NOSPACE);
12759742fdb4Schristos 			}
1276e2b1b9c0Schristos 			label = origin->ndata;
1277e2b1b9c0Schristos 			n1 = origin->length;
1278e2b1b9c0Schristos 			nrem -= n1;
1279e2b1b9c0Schristos 			POST(nrem);
1280e2b1b9c0Schristos 			while (n1 > 0) {
1281e2b1b9c0Schristos 				n2 = *label++;
1282e2b1b9c0Schristos 				INSIST(n2 <= 63); /* no bitstring support */
1283e2b1b9c0Schristos 				*ndata++ = n2;
1284e2b1b9c0Schristos 				n1 -= n2 + 1;
1285e2b1b9c0Schristos 				nused += n2 + 1;
1286e2b1b9c0Schristos 				while (n2 > 0) {
1287e2b1b9c0Schristos 					c = *label++;
12889742fdb4Schristos 					if (downcase) {
1289e2b1b9c0Schristos 						c = maptolower[c & 0xff];
12909742fdb4Schristos 					}
1291e2b1b9c0Schristos 					*ndata++ = c;
1292e2b1b9c0Schristos 					n2--;
1293e2b1b9c0Schristos 				}
1294e2b1b9c0Schristos 				labels++;
1295e2b1b9c0Schristos 				if (n1 > 0) {
1296e2b1b9c0Schristos 					INSIST(labels <= 127);
1297e2b1b9c0Schristos 					offsets[labels] = nused;
1298e2b1b9c0Schristos 				}
1299e2b1b9c0Schristos 			}
13009742fdb4Schristos 			if ((origin->attributes & DNS_NAMEATTR_ABSOLUTE) != 0) {
1301e2b1b9c0Schristos 				name->attributes |= DNS_NAMEATTR_ABSOLUTE;
1302e2b1b9c0Schristos 			}
13039742fdb4Schristos 		}
13049742fdb4Schristos 	} else {
1305e2b1b9c0Schristos 		name->attributes |= DNS_NAMEATTR_ABSOLUTE;
13069742fdb4Schristos 	}
1307e2b1b9c0Schristos 
1308e2b1b9c0Schristos 	name->ndata = (unsigned char *)target->base + target->used;
1309e2b1b9c0Schristos 	name->labels = labels;
1310e2b1b9c0Schristos 	name->length = nused;
1311e2b1b9c0Schristos 
1312e2b1b9c0Schristos 	isc_buffer_forward(source, tused);
1313e2b1b9c0Schristos 	isc_buffer_add(target, name->length);
1314e2b1b9c0Schristos 
1315e2b1b9c0Schristos 	return (ISC_R_SUCCESS);
1316e2b1b9c0Schristos }
1317e2b1b9c0Schristos 
1318e2b1b9c0Schristos isc_result_t
dns_name_totext(const dns_name_t * name,bool omit_final_dot,isc_buffer_t * target)1319f2e20987Schristos dns_name_totext(const dns_name_t *name, bool omit_final_dot,
13209742fdb4Schristos 		isc_buffer_t *target) {
1321e2b1b9c0Schristos 	unsigned int options = DNS_NAME_MASTERFILE;
1322e2b1b9c0Schristos 
13239742fdb4Schristos 	if (omit_final_dot) {
1324e2b1b9c0Schristos 		options |= DNS_NAME_OMITFINALDOT;
13259742fdb4Schristos 	}
1326e2b1b9c0Schristos 	return (dns_name_totext2(name, options, target));
1327e2b1b9c0Schristos }
1328e2b1b9c0Schristos 
1329e2b1b9c0Schristos isc_result_t
dns_name_toprincipal(const dns_name_t * name,isc_buffer_t * target)1330e2b1b9c0Schristos dns_name_toprincipal(const dns_name_t *name, isc_buffer_t *target) {
1331e2b1b9c0Schristos 	return (dns_name_totext2(name, DNS_NAME_OMITFINALDOT, target));
1332e2b1b9c0Schristos }
1333e2b1b9c0Schristos 
1334e2b1b9c0Schristos isc_result_t
dns_name_totext2(const dns_name_t * name,unsigned int options,isc_buffer_t * target)1335e2b1b9c0Schristos dns_name_totext2(const dns_name_t *name, unsigned int options,
13369742fdb4Schristos 		 isc_buffer_t *target) {
1337e2b1b9c0Schristos 	unsigned char *ndata;
1338e2b1b9c0Schristos 	char *tdata;
1339e2b1b9c0Schristos 	unsigned int nlen, tlen;
1340e2b1b9c0Schristos 	unsigned char c;
1341e2b1b9c0Schristos 	unsigned int trem, count;
1342e2b1b9c0Schristos 	unsigned int labels;
1343f2e20987Schristos 	bool saw_root = false;
13448b4c8a26Schristos 	unsigned int oused;
1345f2e20987Schristos 	bool omit_final_dot = ((options & DNS_NAME_OMITFINALDOT) != 0);
1346e2b1b9c0Schristos 
1347e2b1b9c0Schristos 	/*
1348e2b1b9c0Schristos 	 * This function assumes the name is in proper uncompressed
1349e2b1b9c0Schristos 	 * wire format.
1350e2b1b9c0Schristos 	 */
1351e2b1b9c0Schristos 	REQUIRE(VALID_NAME(name));
1352e2b1b9c0Schristos 	REQUIRE(ISC_BUFFER_VALID(target));
1353e2b1b9c0Schristos 
13548b4c8a26Schristos 	oused = target->used;
13558b4c8a26Schristos 
1356e2b1b9c0Schristos 	ndata = name->ndata;
1357e2b1b9c0Schristos 	nlen = name->length;
1358e2b1b9c0Schristos 	labels = name->labels;
1359e2b1b9c0Schristos 	tdata = isc_buffer_used(target);
1360e2b1b9c0Schristos 	tlen = isc_buffer_availablelength(target);
1361e2b1b9c0Schristos 
1362e2b1b9c0Schristos 	trem = tlen;
1363e2b1b9c0Schristos 
1364e2b1b9c0Schristos 	if (labels == 0 && nlen == 0) {
1365e2b1b9c0Schristos 		/*
1366e2b1b9c0Schristos 		 * Special handling for an empty name.
1367e2b1b9c0Schristos 		 */
13689742fdb4Schristos 		if (trem == 0) {
1369e2b1b9c0Schristos 			return (ISC_R_NOSPACE);
13709742fdb4Schristos 		}
1371e2b1b9c0Schristos 
1372e2b1b9c0Schristos 		/*
1373e2b1b9c0Schristos 		 * The names of these booleans are misleading in this case.
1374e2b1b9c0Schristos 		 * This empty name is not necessarily from the root node of
1375e2b1b9c0Schristos 		 * the DNS root zone, nor is a final dot going to be included.
1376e2b1b9c0Schristos 		 * They need to be set this way, though, to keep the "@"
1377e2b1b9c0Schristos 		 * from being trounced.
1378e2b1b9c0Schristos 		 */
1379f2e20987Schristos 		saw_root = true;
1380f2e20987Schristos 		omit_final_dot = false;
1381e2b1b9c0Schristos 		*tdata++ = '@';
1382e2b1b9c0Schristos 		trem--;
1383e2b1b9c0Schristos 
1384e2b1b9c0Schristos 		/*
1385e2b1b9c0Schristos 		 * Skip the while() loop.
1386e2b1b9c0Schristos 		 */
1387e2b1b9c0Schristos 		nlen = 0;
1388e2b1b9c0Schristos 	} else if (nlen == 1 && labels == 1 && *ndata == '\0') {
1389e2b1b9c0Schristos 		/*
1390e2b1b9c0Schristos 		 * Special handling for the root label.
1391e2b1b9c0Schristos 		 */
13929742fdb4Schristos 		if (trem == 0) {
1393e2b1b9c0Schristos 			return (ISC_R_NOSPACE);
13949742fdb4Schristos 		}
1395e2b1b9c0Schristos 
1396f2e20987Schristos 		saw_root = true;
1397f2e20987Schristos 		omit_final_dot = false;
1398e2b1b9c0Schristos 		*tdata++ = '.';
1399e2b1b9c0Schristos 		trem--;
1400e2b1b9c0Schristos 
1401e2b1b9c0Schristos 		/*
1402e2b1b9c0Schristos 		 * Skip the while() loop.
1403e2b1b9c0Schristos 		 */
1404e2b1b9c0Schristos 		nlen = 0;
1405e2b1b9c0Schristos 	}
1406e2b1b9c0Schristos 
1407e2b1b9c0Schristos 	while (labels > 0 && nlen > 0 && trem > 0) {
1408e2b1b9c0Schristos 		labels--;
1409e2b1b9c0Schristos 		count = *ndata++;
1410e2b1b9c0Schristos 		nlen--;
1411e2b1b9c0Schristos 		if (count == 0) {
1412f2e20987Schristos 			saw_root = true;
1413e2b1b9c0Schristos 			break;
1414e2b1b9c0Schristos 		}
1415e2b1b9c0Schristos 		if (count < 64) {
1416e2b1b9c0Schristos 			INSIST(nlen >= count);
1417e2b1b9c0Schristos 			while (count > 0) {
1418e2b1b9c0Schristos 				c = *ndata;
1419e2b1b9c0Schristos 				switch (c) {
1420e2b1b9c0Schristos 				/* Special modifiers in zone files. */
1421e2b1b9c0Schristos 				case 0x40: /* '@' */
1422e2b1b9c0Schristos 				case 0x24: /* '$' */
14239742fdb4Schristos 					if ((options & DNS_NAME_MASTERFILE) ==
1424*4ac1c27eSchristos 					    0)
1425*4ac1c27eSchristos 					{
1426e2b1b9c0Schristos 						goto no_escape;
14279742fdb4Schristos 					}
1428c0b5d9fbSchristos 					FALLTHROUGH;
1429e2b1b9c0Schristos 				case 0x22: /* '"' */
1430e2b1b9c0Schristos 				case 0x28: /* '(' */
1431e2b1b9c0Schristos 				case 0x29: /* ')' */
1432e2b1b9c0Schristos 				case 0x2E: /* '.' */
1433e2b1b9c0Schristos 				case 0x3B: /* ';' */
1434e2b1b9c0Schristos 				case 0x5C: /* '\\' */
14359742fdb4Schristos 					if (trem < 2) {
1436e2b1b9c0Schristos 						return (ISC_R_NOSPACE);
14379742fdb4Schristos 					}
1438e2b1b9c0Schristos 					*tdata++ = '\\';
1439e2b1b9c0Schristos 					CONVERTFROMASCII(c);
1440e2b1b9c0Schristos 					*tdata++ = c;
1441e2b1b9c0Schristos 					ndata++;
1442e2b1b9c0Schristos 					trem -= 2;
1443e2b1b9c0Schristos 					nlen--;
1444e2b1b9c0Schristos 					break;
1445e2b1b9c0Schristos 				no_escape:
1446e2b1b9c0Schristos 				default:
1447e2b1b9c0Schristos 					if (c > 0x20 && c < 0x7f) {
14489742fdb4Schristos 						if (trem == 0) {
1449e2b1b9c0Schristos 							return (ISC_R_NOSPACE);
14509742fdb4Schristos 						}
1451e2b1b9c0Schristos 						CONVERTFROMASCII(c);
1452e2b1b9c0Schristos 						*tdata++ = c;
1453e2b1b9c0Schristos 						ndata++;
1454e2b1b9c0Schristos 						trem--;
1455e2b1b9c0Schristos 						nlen--;
1456e2b1b9c0Schristos 					} else {
14579742fdb4Schristos 						if (trem < 4) {
1458e2b1b9c0Schristos 							return (ISC_R_NOSPACE);
14599742fdb4Schristos 						}
1460e2b1b9c0Schristos 						*tdata++ = 0x5c;
1461e2b1b9c0Schristos 						*tdata++ = 0x30 +
1462e2b1b9c0Schristos 							   ((c / 100) % 10);
1463e2b1b9c0Schristos 						*tdata++ = 0x30 +
1464e2b1b9c0Schristos 							   ((c / 10) % 10);
1465e2b1b9c0Schristos 						*tdata++ = 0x30 + (c % 10);
1466e2b1b9c0Schristos 						trem -= 4;
1467e2b1b9c0Schristos 						ndata++;
1468e2b1b9c0Schristos 						nlen--;
1469e2b1b9c0Schristos 					}
1470e2b1b9c0Schristos 				}
1471e2b1b9c0Schristos 				count--;
1472e2b1b9c0Schristos 			}
1473e2b1b9c0Schristos 		} else {
1474e2b1b9c0Schristos 			FATAL_ERROR(__FILE__, __LINE__,
1475e2b1b9c0Schristos 				    "Unexpected label type %02x", count);
1476c0b5d9fbSchristos 			UNREACHABLE();
1477e2b1b9c0Schristos 		}
1478e2b1b9c0Schristos 
1479e2b1b9c0Schristos 		/*
1480e2b1b9c0Schristos 		 * The following assumes names are absolute.  If not, we
1481e2b1b9c0Schristos 		 * fix things up later.  Note that this means that in some
1482e2b1b9c0Schristos 		 * cases one more byte of text buffer is required than is
1483e2b1b9c0Schristos 		 * needed in the final output.
1484e2b1b9c0Schristos 		 */
14859742fdb4Schristos 		if (trem == 0) {
1486e2b1b9c0Schristos 			return (ISC_R_NOSPACE);
14879742fdb4Schristos 		}
1488e2b1b9c0Schristos 		*tdata++ = '.';
1489e2b1b9c0Schristos 		trem--;
1490e2b1b9c0Schristos 	}
1491e2b1b9c0Schristos 
14929742fdb4Schristos 	if (nlen != 0 && trem == 0) {
1493e2b1b9c0Schristos 		return (ISC_R_NOSPACE);
14949742fdb4Schristos 	}
1495e2b1b9c0Schristos 
1496e2b1b9c0Schristos 	if (!saw_root || omit_final_dot) {
1497e2b1b9c0Schristos 		trem++;
1498e2b1b9c0Schristos 		tdata--;
1499e2b1b9c0Schristos 	}
1500e2b1b9c0Schristos 	if (trem > 0) {
1501e2b1b9c0Schristos 		*tdata = 0;
1502e2b1b9c0Schristos 	}
1503e2b1b9c0Schristos 	isc_buffer_add(target, tlen - trem);
1504e2b1b9c0Schristos 
15059742fdb4Schristos 	if (totext_filter_proc != NULL) {
15069742fdb4Schristos 		return ((totext_filter_proc)(target, oused));
15079742fdb4Schristos 	}
1508e2b1b9c0Schristos 
1509e2b1b9c0Schristos 	return (ISC_R_SUCCESS);
1510e2b1b9c0Schristos }
1511e2b1b9c0Schristos 
1512e2b1b9c0Schristos isc_result_t
dns_name_tofilenametext(const dns_name_t * name,bool omit_final_dot,isc_buffer_t * target)1513f2e20987Schristos dns_name_tofilenametext(const dns_name_t *name, bool omit_final_dot,
15149742fdb4Schristos 			isc_buffer_t *target) {
1515e2b1b9c0Schristos 	unsigned char *ndata;
1516e2b1b9c0Schristos 	char *tdata;
1517e2b1b9c0Schristos 	unsigned int nlen, tlen;
1518e2b1b9c0Schristos 	unsigned char c;
1519e2b1b9c0Schristos 	unsigned int trem, count;
1520e2b1b9c0Schristos 	unsigned int labels;
1521e2b1b9c0Schristos 
1522e2b1b9c0Schristos 	/*
1523e2b1b9c0Schristos 	 * This function assumes the name is in proper uncompressed
1524e2b1b9c0Schristos 	 * wire format.
1525e2b1b9c0Schristos 	 */
1526e2b1b9c0Schristos 	REQUIRE(VALID_NAME(name));
1527e2b1b9c0Schristos 	REQUIRE((name->attributes & DNS_NAMEATTR_ABSOLUTE) != 0);
1528e2b1b9c0Schristos 	REQUIRE(ISC_BUFFER_VALID(target));
1529e2b1b9c0Schristos 
1530e2b1b9c0Schristos 	ndata = name->ndata;
1531e2b1b9c0Schristos 	nlen = name->length;
1532e2b1b9c0Schristos 	labels = name->labels;
1533e2b1b9c0Schristos 	tdata = isc_buffer_used(target);
1534e2b1b9c0Schristos 	tlen = isc_buffer_availablelength(target);
1535e2b1b9c0Schristos 
1536e2b1b9c0Schristos 	trem = tlen;
1537e2b1b9c0Schristos 
1538e2b1b9c0Schristos 	if (nlen == 1 && labels == 1 && *ndata == '\0') {
1539e2b1b9c0Schristos 		/*
1540e2b1b9c0Schristos 		 * Special handling for the root label.
1541e2b1b9c0Schristos 		 */
15429742fdb4Schristos 		if (trem == 0) {
1543e2b1b9c0Schristos 			return (ISC_R_NOSPACE);
15449742fdb4Schristos 		}
1545e2b1b9c0Schristos 
1546f2e20987Schristos 		omit_final_dot = false;
1547e2b1b9c0Schristos 		*tdata++ = '.';
1548e2b1b9c0Schristos 		trem--;
1549e2b1b9c0Schristos 
1550e2b1b9c0Schristos 		/*
1551e2b1b9c0Schristos 		 * Skip the while() loop.
1552e2b1b9c0Schristos 		 */
1553e2b1b9c0Schristos 		nlen = 0;
1554e2b1b9c0Schristos 	}
1555e2b1b9c0Schristos 
1556e2b1b9c0Schristos 	while (labels > 0 && nlen > 0 && trem > 0) {
1557e2b1b9c0Schristos 		labels--;
1558e2b1b9c0Schristos 		count = *ndata++;
1559e2b1b9c0Schristos 		nlen--;
15609742fdb4Schristos 		if (count == 0) {
1561e2b1b9c0Schristos 			break;
15629742fdb4Schristos 		}
1563e2b1b9c0Schristos 		if (count < 64) {
1564e2b1b9c0Schristos 			INSIST(nlen >= count);
1565e2b1b9c0Schristos 			while (count > 0) {
1566e2b1b9c0Schristos 				c = *ndata;
1567e2b1b9c0Schristos 				if ((c >= 0x30 && c <= 0x39) || /* digit */
1568e2b1b9c0Schristos 				    (c >= 0x41 && c <= 0x5A) || /* uppercase */
1569e2b1b9c0Schristos 				    (c >= 0x61 && c <= 0x7A) || /* lowercase */
1570e2b1b9c0Schristos 				    c == 0x2D ||		/* hyphen */
1571e2b1b9c0Schristos 				    c == 0x5F)			/* underscore */
1572e2b1b9c0Schristos 				{
15739742fdb4Schristos 					if (trem == 0) {
1574e2b1b9c0Schristos 						return (ISC_R_NOSPACE);
15759742fdb4Schristos 					}
1576e2b1b9c0Schristos 					/* downcase */
15779742fdb4Schristos 					if (c >= 0x41 && c <= 0x5A) {
1578e2b1b9c0Schristos 						c += 0x20;
15799742fdb4Schristos 					}
1580e2b1b9c0Schristos 					CONVERTFROMASCII(c);
1581e2b1b9c0Schristos 					*tdata++ = c;
1582e2b1b9c0Schristos 					ndata++;
1583e2b1b9c0Schristos 					trem--;
1584e2b1b9c0Schristos 					nlen--;
1585e2b1b9c0Schristos 				} else {
15869742fdb4Schristos 					if (trem < 4) {
1587e2b1b9c0Schristos 						return (ISC_R_NOSPACE);
15889742fdb4Schristos 					}
1589e2b1b9c0Schristos 					snprintf(tdata, trem, "%%%02X", c);
1590e2b1b9c0Schristos 					tdata += 3;
1591e2b1b9c0Schristos 					trem -= 3;
1592e2b1b9c0Schristos 					ndata++;
1593e2b1b9c0Schristos 					nlen--;
1594e2b1b9c0Schristos 				}
1595e2b1b9c0Schristos 				count--;
1596e2b1b9c0Schristos 			}
1597e2b1b9c0Schristos 		} else {
1598e2b1b9c0Schristos 			FATAL_ERROR(__FILE__, __LINE__,
1599e2b1b9c0Schristos 				    "Unexpected label type %02x", count);
1600c0b5d9fbSchristos 			UNREACHABLE();
1601e2b1b9c0Schristos 		}
1602e2b1b9c0Schristos 
1603e2b1b9c0Schristos 		/*
1604e2b1b9c0Schristos 		 * The following assumes names are absolute.  If not, we
1605e2b1b9c0Schristos 		 * fix things up later.  Note that this means that in some
1606e2b1b9c0Schristos 		 * cases one more byte of text buffer is required than is
1607e2b1b9c0Schristos 		 * needed in the final output.
1608e2b1b9c0Schristos 		 */
16099742fdb4Schristos 		if (trem == 0) {
1610e2b1b9c0Schristos 			return (ISC_R_NOSPACE);
16119742fdb4Schristos 		}
1612e2b1b9c0Schristos 		*tdata++ = '.';
1613e2b1b9c0Schristos 		trem--;
1614e2b1b9c0Schristos 	}
1615e2b1b9c0Schristos 
16169742fdb4Schristos 	if (nlen != 0 && trem == 0) {
1617e2b1b9c0Schristos 		return (ISC_R_NOSPACE);
16189742fdb4Schristos 	}
1619e2b1b9c0Schristos 
16209742fdb4Schristos 	if (omit_final_dot) {
1621e2b1b9c0Schristos 		trem++;
16229742fdb4Schristos 	}
1623e2b1b9c0Schristos 
1624e2b1b9c0Schristos 	isc_buffer_add(target, tlen - trem);
1625e2b1b9c0Schristos 
1626e2b1b9c0Schristos 	return (ISC_R_SUCCESS);
1627e2b1b9c0Schristos }
1628e2b1b9c0Schristos 
1629e2b1b9c0Schristos isc_result_t
dns_name_downcase(const dns_name_t * source,dns_name_t * name,isc_buffer_t * target)1630e2b1b9c0Schristos dns_name_downcase(const dns_name_t *source, dns_name_t *name,
16319742fdb4Schristos 		  isc_buffer_t *target) {
1632e2b1b9c0Schristos 	unsigned char *sndata, *ndata;
1633e2b1b9c0Schristos 	unsigned int nlen, count, labels;
1634e2b1b9c0Schristos 	isc_buffer_t buffer;
1635e2b1b9c0Schristos 
1636e2b1b9c0Schristos 	/*
1637e2b1b9c0Schristos 	 * Downcase 'source'.
1638e2b1b9c0Schristos 	 */
1639e2b1b9c0Schristos 
1640e2b1b9c0Schristos 	REQUIRE(VALID_NAME(source));
1641e2b1b9c0Schristos 	REQUIRE(VALID_NAME(name));
1642e2b1b9c0Schristos 	if (source == name) {
1643e2b1b9c0Schristos 		REQUIRE((name->attributes & DNS_NAMEATTR_READONLY) == 0);
1644e2b1b9c0Schristos 		isc_buffer_init(&buffer, source->ndata, source->length);
1645e2b1b9c0Schristos 		target = &buffer;
1646e2b1b9c0Schristos 		ndata = source->ndata;
1647e2b1b9c0Schristos 	} else {
1648e2b1b9c0Schristos 		REQUIRE(BINDABLE(name));
1649e2b1b9c0Schristos 		REQUIRE((target != NULL && ISC_BUFFER_VALID(target)) ||
1650e2b1b9c0Schristos 			(target == NULL && ISC_BUFFER_VALID(name->buffer)));
1651e2b1b9c0Schristos 		if (target == NULL) {
1652e2b1b9c0Schristos 			target = name->buffer;
1653e2b1b9c0Schristos 			isc_buffer_clear(name->buffer);
1654e2b1b9c0Schristos 		}
1655e2b1b9c0Schristos 		ndata = (unsigned char *)target->base + target->used;
1656e2b1b9c0Schristos 		name->ndata = ndata;
1657e2b1b9c0Schristos 	}
1658e2b1b9c0Schristos 
1659e2b1b9c0Schristos 	sndata = source->ndata;
1660e2b1b9c0Schristos 	nlen = source->length;
1661e2b1b9c0Schristos 	labels = source->labels;
1662e2b1b9c0Schristos 
1663e2b1b9c0Schristos 	if (nlen > (target->length - target->used)) {
1664e2b1b9c0Schristos 		MAKE_EMPTY(name);
1665e2b1b9c0Schristos 		return (ISC_R_NOSPACE);
1666e2b1b9c0Schristos 	}
1667e2b1b9c0Schristos 
1668e2b1b9c0Schristos 	while (labels > 0 && nlen > 0) {
1669e2b1b9c0Schristos 		labels--;
1670e2b1b9c0Schristos 		count = *sndata++;
1671e2b1b9c0Schristos 		*ndata++ = count;
1672e2b1b9c0Schristos 		nlen--;
1673e2b1b9c0Schristos 		if (count < 64) {
1674e2b1b9c0Schristos 			INSIST(nlen >= count);
1675e2b1b9c0Schristos 			while (count > 0) {
1676e2b1b9c0Schristos 				*ndata++ = maptolower[(*sndata++)];
1677e2b1b9c0Schristos 				nlen--;
1678e2b1b9c0Schristos 				count--;
1679e2b1b9c0Schristos 			}
1680e2b1b9c0Schristos 		} else {
1681e2b1b9c0Schristos 			FATAL_ERROR(__FILE__, __LINE__,
1682e2b1b9c0Schristos 				    "Unexpected label type %02x", count);
1683e2b1b9c0Schristos 			/* Does not return. */
1684e2b1b9c0Schristos 		}
1685e2b1b9c0Schristos 	}
1686e2b1b9c0Schristos 
1687e2b1b9c0Schristos 	if (source != name) {
1688e2b1b9c0Schristos 		name->labels = source->labels;
1689e2b1b9c0Schristos 		name->length = source->length;
16909742fdb4Schristos 		if ((source->attributes & DNS_NAMEATTR_ABSOLUTE) != 0) {
1691e2b1b9c0Schristos 			name->attributes = DNS_NAMEATTR_ABSOLUTE;
16929742fdb4Schristos 		} else {
1693e2b1b9c0Schristos 			name->attributes = 0;
16949742fdb4Schristos 		}
16959742fdb4Schristos 		if (name->labels > 0 && name->offsets != NULL) {
1696e2b1b9c0Schristos 			set_offsets(name, name->offsets, NULL);
1697e2b1b9c0Schristos 		}
16989742fdb4Schristos 	}
1699e2b1b9c0Schristos 
1700e2b1b9c0Schristos 	isc_buffer_add(target, name->length);
1701e2b1b9c0Schristos 
1702e2b1b9c0Schristos 	return (ISC_R_SUCCESS);
1703e2b1b9c0Schristos }
1704e2b1b9c0Schristos 
1705e2b1b9c0Schristos static void
set_offsets(const dns_name_t * name,unsigned char * offsets,dns_name_t * set_name)1706e2b1b9c0Schristos set_offsets(const dns_name_t *name, unsigned char *offsets,
17079742fdb4Schristos 	    dns_name_t *set_name) {
1708e2b1b9c0Schristos 	unsigned int offset, count, length, nlabels;
1709e2b1b9c0Schristos 	unsigned char *ndata;
1710f2e20987Schristos 	bool absolute;
1711e2b1b9c0Schristos 
1712e2b1b9c0Schristos 	ndata = name->ndata;
1713e2b1b9c0Schristos 	length = name->length;
1714e2b1b9c0Schristos 	offset = 0;
1715e2b1b9c0Schristos 	nlabels = 0;
1716f2e20987Schristos 	absolute = false;
1717e2b1b9c0Schristos 	while (ISC_LIKELY(offset != length)) {
1718e2b1b9c0Schristos 		INSIST(nlabels < 128);
1719e2b1b9c0Schristos 		offsets[nlabels++] = offset;
1720e2b1b9c0Schristos 		count = *ndata;
1721e2b1b9c0Schristos 		INSIST(count <= 63);
1722e2b1b9c0Schristos 		offset += count + 1;
1723e2b1b9c0Schristos 		ndata += count + 1;
1724e2b1b9c0Schristos 		INSIST(offset <= length);
1725e2b1b9c0Schristos 		if (ISC_UNLIKELY(count == 0)) {
1726f2e20987Schristos 			absolute = true;
1727e2b1b9c0Schristos 			break;
1728e2b1b9c0Schristos 		}
1729e2b1b9c0Schristos 	}
1730e2b1b9c0Schristos 	if (set_name != NULL) {
1731e2b1b9c0Schristos 		INSIST(set_name == name);
1732e2b1b9c0Schristos 
1733e2b1b9c0Schristos 		set_name->labels = nlabels;
1734e2b1b9c0Schristos 		set_name->length = offset;
17359742fdb4Schristos 		if (absolute) {
1736e2b1b9c0Schristos 			set_name->attributes |= DNS_NAMEATTR_ABSOLUTE;
17379742fdb4Schristos 		} else {
1738e2b1b9c0Schristos 			set_name->attributes &= ~DNS_NAMEATTR_ABSOLUTE;
1739e2b1b9c0Schristos 		}
17409742fdb4Schristos 	}
1741e2b1b9c0Schristos 	INSIST(nlabels == name->labels);
1742e2b1b9c0Schristos 	INSIST(offset == name->length);
1743e2b1b9c0Schristos }
1744e2b1b9c0Schristos 
1745e2b1b9c0Schristos isc_result_t
dns_name_fromwire(dns_name_t * name,isc_buffer_t * source,dns_decompress_t * dctx,unsigned int options,isc_buffer_t * target)1746e2b1b9c0Schristos dns_name_fromwire(dns_name_t *name, isc_buffer_t *source,
1747e2b1b9c0Schristos 		  dns_decompress_t *dctx, unsigned int options,
17489742fdb4Schristos 		  isc_buffer_t *target) {
1749e2b1b9c0Schristos 	unsigned char *cdata, *ndata;
1750e2b1b9c0Schristos 	unsigned int cused; /* Bytes of compressed name data used */
1751e2b1b9c0Schristos 	unsigned int nused, labels, n, nmax;
1752e2b1b9c0Schristos 	unsigned int current, new_current, biggest_pointer;
1753f2e20987Schristos 	bool done;
1754e2b1b9c0Schristos 	fw_state state = fw_start;
1755e2b1b9c0Schristos 	unsigned int c;
1756e2b1b9c0Schristos 	unsigned char *offsets;
1757e2b1b9c0Schristos 	dns_offsets_t odata;
1758f2e20987Schristos 	bool downcase;
1759f2e20987Schristos 	bool seen_pointer;
1760e2b1b9c0Schristos 
1761e2b1b9c0Schristos 	/*
1762e2b1b9c0Schristos 	 * Copy the possibly-compressed name at source into target,
1763e2b1b9c0Schristos 	 * decompressing it.  Loop prevention is performed by checking
1764e2b1b9c0Schristos 	 * the new pointer against biggest_pointer.
1765e2b1b9c0Schristos 	 */
1766e2b1b9c0Schristos 
1767e2b1b9c0Schristos 	REQUIRE(VALID_NAME(name));
1768e2b1b9c0Schristos 	REQUIRE((target != NULL && ISC_BUFFER_VALID(target)) ||
1769e2b1b9c0Schristos 		(target == NULL && ISC_BUFFER_VALID(name->buffer)));
1770e2b1b9c0Schristos 
1771f2e20987Schristos 	downcase = ((options & DNS_NAME_DOWNCASE) != 0);
1772e2b1b9c0Schristos 
1773e2b1b9c0Schristos 	if (target == NULL && name->buffer != NULL) {
1774e2b1b9c0Schristos 		target = name->buffer;
1775e2b1b9c0Schristos 		isc_buffer_clear(target);
1776e2b1b9c0Schristos 	}
1777e2b1b9c0Schristos 
1778e2b1b9c0Schristos 	REQUIRE(dctx != NULL);
1779e2b1b9c0Schristos 	REQUIRE(BINDABLE(name));
1780e2b1b9c0Schristos 
1781e2b1b9c0Schristos 	INIT_OFFSETS(name, offsets, odata);
1782e2b1b9c0Schristos 
1783e2b1b9c0Schristos 	/*
1784e2b1b9c0Schristos 	 * Make 'name' empty in case of failure.
1785e2b1b9c0Schristos 	 */
1786e2b1b9c0Schristos 	MAKE_EMPTY(name);
1787e2b1b9c0Schristos 
1788e2b1b9c0Schristos 	/*
1789e2b1b9c0Schristos 	 * Initialize things to make the compiler happy; they're not required.
1790e2b1b9c0Schristos 	 */
1791e2b1b9c0Schristos 	n = 0;
1792e2b1b9c0Schristos 	new_current = 0;
1793e2b1b9c0Schristos 
1794e2b1b9c0Schristos 	/*
1795e2b1b9c0Schristos 	 * Set up.
1796e2b1b9c0Schristos 	 */
1797e2b1b9c0Schristos 	labels = 0;
1798f2e20987Schristos 	done = false;
1799e2b1b9c0Schristos 
1800e2b1b9c0Schristos 	ndata = isc_buffer_used(target);
1801e2b1b9c0Schristos 	nused = 0;
1802f2e20987Schristos 	seen_pointer = false;
1803e2b1b9c0Schristos 
1804e2b1b9c0Schristos 	/*
1805e2b1b9c0Schristos 	 * Find the maximum number of uncompressed target name
1806e2b1b9c0Schristos 	 * bytes we are willing to generate.  This is the smaller
1807e2b1b9c0Schristos 	 * of the available target buffer length and the
1808e2b1b9c0Schristos 	 * maximum legal domain name length (255).
1809e2b1b9c0Schristos 	 */
1810e2b1b9c0Schristos 	nmax = isc_buffer_availablelength(target);
18119742fdb4Schristos 	if (nmax > DNS_NAME_MAXWIRE) {
1812e2b1b9c0Schristos 		nmax = DNS_NAME_MAXWIRE;
18139742fdb4Schristos 	}
1814e2b1b9c0Schristos 
1815e2b1b9c0Schristos 	cdata = isc_buffer_current(source);
1816e2b1b9c0Schristos 	cused = 0;
1817e2b1b9c0Schristos 
1818e2b1b9c0Schristos 	current = source->current;
1819e2b1b9c0Schristos 	biggest_pointer = current;
1820e2b1b9c0Schristos 
1821e2b1b9c0Schristos 	/*
1822e2b1b9c0Schristos 	 * Note:  The following code is not optimized for speed, but
1823e2b1b9c0Schristos 	 * rather for correctness.  Speed will be addressed in the future.
1824e2b1b9c0Schristos 	 */
1825e2b1b9c0Schristos 
1826e2b1b9c0Schristos 	while (current < source->active && !done) {
1827e2b1b9c0Schristos 		c = *cdata++;
1828e2b1b9c0Schristos 		current++;
18299742fdb4Schristos 		if (!seen_pointer) {
1830e2b1b9c0Schristos 			cused++;
18319742fdb4Schristos 		}
1832e2b1b9c0Schristos 
1833e2b1b9c0Schristos 		switch (state) {
1834e2b1b9c0Schristos 		case fw_start:
1835e2b1b9c0Schristos 			if (c < 64) {
1836e2b1b9c0Schristos 				offsets[labels] = nused;
1837e2b1b9c0Schristos 				labels++;
18389742fdb4Schristos 				if (nused + c + 1 > nmax) {
1839e2b1b9c0Schristos 					goto full;
18409742fdb4Schristos 				}
1841e2b1b9c0Schristos 				nused += c + 1;
1842e2b1b9c0Schristos 				*ndata++ = c;
18439742fdb4Schristos 				if (c == 0) {
1844f2e20987Schristos 					done = true;
18459742fdb4Schristos 				}
1846e2b1b9c0Schristos 				n = c;
1847e2b1b9c0Schristos 				state = fw_ordinary;
1848e2b1b9c0Schristos 			} else if (c >= 128 && c < 192) {
1849e2b1b9c0Schristos 				/*
1850e2b1b9c0Schristos 				 * 14 bit local compression pointer.
1851e2b1b9c0Schristos 				 * Local compression is no longer an
1852e2b1b9c0Schristos 				 * IETF draft.
1853e2b1b9c0Schristos 				 */
1854e2b1b9c0Schristos 				return (DNS_R_BADLABELTYPE);
1855e2b1b9c0Schristos 			} else if (c >= 192) {
1856e2b1b9c0Schristos 				/*
1857e2b1b9c0Schristos 				 * Ordinary 14-bit pointer.
1858e2b1b9c0Schristos 				 */
18599742fdb4Schristos 				if ((dctx->allowed & DNS_COMPRESS_GLOBAL14) ==
1860*4ac1c27eSchristos 				    0)
1861*4ac1c27eSchristos 				{
1862e2b1b9c0Schristos 					return (DNS_R_DISALLOWED);
1863f2e20987Schristos 				}
1864e2b1b9c0Schristos 				new_current = c & 0x3F;
1865e2b1b9c0Schristos 				state = fw_newcurrent;
18669742fdb4Schristos 			} else {
1867e2b1b9c0Schristos 				return (DNS_R_BADLABELTYPE);
18689742fdb4Schristos 			}
1869e2b1b9c0Schristos 			break;
1870e2b1b9c0Schristos 		case fw_ordinary:
18719742fdb4Schristos 			if (downcase) {
1872e2b1b9c0Schristos 				c = maptolower[c];
18739742fdb4Schristos 			}
1874e2b1b9c0Schristos 			*ndata++ = c;
1875e2b1b9c0Schristos 			n--;
18769742fdb4Schristos 			if (n == 0) {
1877e2b1b9c0Schristos 				state = fw_start;
18789742fdb4Schristos 			}
1879e2b1b9c0Schristos 			break;
1880e2b1b9c0Schristos 		case fw_newcurrent:
1881e2b1b9c0Schristos 			new_current *= 256;
1882e2b1b9c0Schristos 			new_current += c;
18839742fdb4Schristos 			if (new_current >= biggest_pointer) {
1884e2b1b9c0Schristos 				return (DNS_R_BADPOINTER);
18859742fdb4Schristos 			}
1886e2b1b9c0Schristos 			biggest_pointer = new_current;
1887e2b1b9c0Schristos 			current = new_current;
1888e2b1b9c0Schristos 			cdata = (unsigned char *)source->base + current;
1889f2e20987Schristos 			seen_pointer = true;
1890e2b1b9c0Schristos 			state = fw_start;
1891e2b1b9c0Schristos 			break;
1892e2b1b9c0Schristos 		default:
18939742fdb4Schristos 			FATAL_ERROR(__FILE__, __LINE__, "Unknown state %d",
18949742fdb4Schristos 				    state);
1895e2b1b9c0Schristos 			/* Does not return. */
1896e2b1b9c0Schristos 		}
1897e2b1b9c0Schristos 	}
1898e2b1b9c0Schristos 
18999742fdb4Schristos 	if (!done) {
1900e2b1b9c0Schristos 		return (ISC_R_UNEXPECTEDEND);
19019742fdb4Schristos 	}
1902e2b1b9c0Schristos 
1903e2b1b9c0Schristos 	name->ndata = (unsigned char *)target->base + target->used;
1904e2b1b9c0Schristos 	name->labels = labels;
1905e2b1b9c0Schristos 	name->length = nused;
1906e2b1b9c0Schristos 	name->attributes |= DNS_NAMEATTR_ABSOLUTE;
1907e2b1b9c0Schristos 
1908e2b1b9c0Schristos 	isc_buffer_forward(source, cused);
1909e2b1b9c0Schristos 	isc_buffer_add(target, name->length);
1910e2b1b9c0Schristos 
1911e2b1b9c0Schristos 	return (ISC_R_SUCCESS);
1912e2b1b9c0Schristos 
1913e2b1b9c0Schristos full:
19149742fdb4Schristos 	if (nmax == DNS_NAME_MAXWIRE) {
1915e2b1b9c0Schristos 		/*
1916e2b1b9c0Schristos 		 * The name did not fit even though we had a buffer
1917e2b1b9c0Schristos 		 * big enough to fit a maximum-length name.
1918e2b1b9c0Schristos 		 */
1919e2b1b9c0Schristos 		return (DNS_R_NAMETOOLONG);
19209742fdb4Schristos 	} else {
1921e2b1b9c0Schristos 		/*
1922e2b1b9c0Schristos 		 * The name might fit if only the caller could give us a
1923e2b1b9c0Schristos 		 * big enough buffer.
1924e2b1b9c0Schristos 		 */
1925e2b1b9c0Schristos 		return (ISC_R_NOSPACE);
1926e2b1b9c0Schristos 	}
19279742fdb4Schristos }
1928e2b1b9c0Schristos 
1929e2b1b9c0Schristos isc_result_t
dns_name_towire(const dns_name_t * name,dns_compress_t * cctx,isc_buffer_t * target)1930e2b1b9c0Schristos dns_name_towire(const dns_name_t *name, dns_compress_t *cctx,
19319742fdb4Schristos 		isc_buffer_t *target) {
1932e2b1b9c0Schristos 	return (dns_name_towire2(name, cctx, target, NULL));
1933e2b1b9c0Schristos }
1934e2b1b9c0Schristos 
1935e2b1b9c0Schristos isc_result_t
dns_name_towire2(const dns_name_t * name,dns_compress_t * cctx,isc_buffer_t * target,uint16_t * comp_offsetp)1936e2b1b9c0Schristos dns_name_towire2(const dns_name_t *name, dns_compress_t *cctx,
19379742fdb4Schristos 		 isc_buffer_t *target, uint16_t *comp_offsetp) {
1938e2b1b9c0Schristos 	unsigned int methods;
1939f2e20987Schristos 	uint16_t offset;
1940e2b1b9c0Schristos 	dns_name_t gp; /* Global compression prefix */
1941f2e20987Schristos 	bool gf;       /* Global compression target found */
1942f2e20987Schristos 	uint16_t go;   /* Global compression offset */
1943e2b1b9c0Schristos 	dns_offsets_t clo;
1944e2b1b9c0Schristos 	dns_name_t clname;
1945e2b1b9c0Schristos 
1946e2b1b9c0Schristos 	/*
1947e2b1b9c0Schristos 	 * Convert 'name' into wire format, compressing it as specified by the
1948e2b1b9c0Schristos 	 * compression context 'cctx', and storing the result in 'target'.
1949e2b1b9c0Schristos 	 */
1950e2b1b9c0Schristos 
1951e2b1b9c0Schristos 	REQUIRE(VALID_NAME(name));
1952e2b1b9c0Schristos 	REQUIRE(cctx != NULL);
1953e2b1b9c0Schristos 	REQUIRE(ISC_BUFFER_VALID(target));
1954e2b1b9c0Schristos 
1955e2b1b9c0Schristos 	/*
1956e2b1b9c0Schristos 	 * If this exact name was already rendered before, and the
1957e2b1b9c0Schristos 	 * offset of the previously rendered name is passed to us, write
1958e2b1b9c0Schristos 	 * a compression pointer directly.
1959e2b1b9c0Schristos 	 */
1960e2b1b9c0Schristos 	methods = dns_compress_getmethods(cctx);
1961e2b1b9c0Schristos 	if (comp_offsetp != NULL && *comp_offsetp < 0x4000 &&
1962e2b1b9c0Schristos 	    (name->attributes & DNS_NAMEATTR_NOCOMPRESS) == 0 &&
19639742fdb4Schristos 	    (methods & DNS_COMPRESS_GLOBAL14) != 0)
19649742fdb4Schristos 	{
19659742fdb4Schristos 		if (ISC_UNLIKELY(target->length - target->used < 2)) {
1966e2b1b9c0Schristos 			return (ISC_R_NOSPACE);
19679742fdb4Schristos 		}
1968e2b1b9c0Schristos 		offset = *comp_offsetp;
1969e2b1b9c0Schristos 		offset |= 0xc000;
1970e2b1b9c0Schristos 		isc_buffer_putuint16(target, offset);
1971e2b1b9c0Schristos 		return (ISC_R_SUCCESS);
1972e2b1b9c0Schristos 	}
1973e2b1b9c0Schristos 
1974e2b1b9c0Schristos 	/*
1975e2b1b9c0Schristos 	 * If 'name' doesn't have an offsets table, make a clone which
1976e2b1b9c0Schristos 	 * has one.
1977e2b1b9c0Schristos 	 */
1978e2b1b9c0Schristos 	if (name->offsets == NULL) {
1979e2b1b9c0Schristos 		DNS_NAME_INIT(&clname, clo);
1980e2b1b9c0Schristos 		dns_name_clone(name, &clname);
1981e2b1b9c0Schristos 		name = &clname;
1982e2b1b9c0Schristos 	}
1983e2b1b9c0Schristos 	DNS_NAME_INIT(&gp, NULL);
1984e2b1b9c0Schristos 
1985e2b1b9c0Schristos 	offset = target->used; /*XXX*/
1986e2b1b9c0Schristos 
1987e2b1b9c0Schristos 	if ((name->attributes & DNS_NAMEATTR_NOCOMPRESS) == 0 &&
1988e2b1b9c0Schristos 	    (methods & DNS_COMPRESS_GLOBAL14) != 0)
19899742fdb4Schristos 	{
1990e2b1b9c0Schristos 		gf = dns_compress_findglobal(cctx, name, &gp, &go);
19919742fdb4Schristos 	} else {
1992f2e20987Schristos 		gf = false;
19939742fdb4Schristos 	}
1994e2b1b9c0Schristos 
1995e2b1b9c0Schristos 	/*
1996e2b1b9c0Schristos 	 * If the offset is too high for 14 bit global compression, we're
1997e2b1b9c0Schristos 	 * out of luck.
1998e2b1b9c0Schristos 	 */
19999742fdb4Schristos 	if (gf && ISC_UNLIKELY(go >= 0x4000)) {
2000f2e20987Schristos 		gf = false;
20019742fdb4Schristos 	}
2002e2b1b9c0Schristos 
2003e2b1b9c0Schristos 	/*
2004e2b1b9c0Schristos 	 * Will the compression pointer reduce the message size?
2005e2b1b9c0Schristos 	 */
20069742fdb4Schristos 	if (gf && (gp.length + 2) >= name->length) {
2007f2e20987Schristos 		gf = false;
20089742fdb4Schristos 	}
2009e2b1b9c0Schristos 
2010e2b1b9c0Schristos 	if (gf) {
20119742fdb4Schristos 		if (ISC_UNLIKELY(target->length - target->used < gp.length)) {
2012e2b1b9c0Schristos 			return (ISC_R_NOSPACE);
20139742fdb4Schristos 		}
2014e2b1b9c0Schristos 		if (gp.length != 0) {
2015e2b1b9c0Schristos 			unsigned char *base = target->base;
2016e2b1b9c0Schristos 			(void)memmove(base + target->used, gp.ndata,
2017e2b1b9c0Schristos 				      (size_t)gp.length);
2018e2b1b9c0Schristos 		}
2019e2b1b9c0Schristos 		isc_buffer_add(target, gp.length);
20209742fdb4Schristos 		if (ISC_UNLIKELY(target->length - target->used < 2)) {
2021e2b1b9c0Schristos 			return (ISC_R_NOSPACE);
20229742fdb4Schristos 		}
2023e2b1b9c0Schristos 		isc_buffer_putuint16(target, go | 0xc000);
2024e2b1b9c0Schristos 		if (gp.length != 0) {
2025e2b1b9c0Schristos 			dns_compress_add(cctx, name, &gp, offset);
20269742fdb4Schristos 			if (comp_offsetp != NULL) {
2027e2b1b9c0Schristos 				*comp_offsetp = offset;
20289742fdb4Schristos 			}
2029e2b1b9c0Schristos 		} else if (comp_offsetp != NULL) {
2030e2b1b9c0Schristos 			*comp_offsetp = go;
2031e2b1b9c0Schristos 		}
2032e2b1b9c0Schristos 	} else {
2033e2b1b9c0Schristos 		if (ISC_UNLIKELY(target->length - target->used < name->length))
20349742fdb4Schristos 		{
2035e2b1b9c0Schristos 			return (ISC_R_NOSPACE);
20369742fdb4Schristos 		}
2037e2b1b9c0Schristos 		if (name->length != 0) {
2038e2b1b9c0Schristos 			unsigned char *base = target->base;
2039e2b1b9c0Schristos 			(void)memmove(base + target->used, name->ndata,
2040e2b1b9c0Schristos 				      (size_t)name->length);
2041e2b1b9c0Schristos 		}
2042e2b1b9c0Schristos 		isc_buffer_add(target, name->length);
2043e2b1b9c0Schristos 		dns_compress_add(cctx, name, name, offset);
20449742fdb4Schristos 		if (comp_offsetp != NULL) {
2045e2b1b9c0Schristos 			*comp_offsetp = offset;
2046e2b1b9c0Schristos 		}
20479742fdb4Schristos 	}
2048e2b1b9c0Schristos 
2049e2b1b9c0Schristos 	return (ISC_R_SUCCESS);
2050e2b1b9c0Schristos }
2051e2b1b9c0Schristos 
2052e2b1b9c0Schristos isc_result_t
dns_name_concatenate(const dns_name_t * prefix,const dns_name_t * suffix,dns_name_t * name,isc_buffer_t * target)2053e2b1b9c0Schristos dns_name_concatenate(const dns_name_t *prefix, const dns_name_t *suffix,
20549742fdb4Schristos 		     dns_name_t *name, isc_buffer_t *target) {
2055e2b1b9c0Schristos 	unsigned char *ndata, *offsets;
2056e2b1b9c0Schristos 	unsigned int nrem, labels, prefix_length, length;
2057f2e20987Schristos 	bool copy_prefix = true;
2058f2e20987Schristos 	bool copy_suffix = true;
2059f2e20987Schristos 	bool absolute = false;
2060e2b1b9c0Schristos 	dns_name_t tmp_name;
2061e2b1b9c0Schristos 	dns_offsets_t odata;
2062e2b1b9c0Schristos 
2063e2b1b9c0Schristos 	/*
2064e2b1b9c0Schristos 	 * Concatenate 'prefix' and 'suffix'.
2065e2b1b9c0Schristos 	 */
2066e2b1b9c0Schristos 
2067e2b1b9c0Schristos 	REQUIRE(prefix == NULL || VALID_NAME(prefix));
2068e2b1b9c0Schristos 	REQUIRE(suffix == NULL || VALID_NAME(suffix));
2069e2b1b9c0Schristos 	REQUIRE(name == NULL || VALID_NAME(name));
2070e2b1b9c0Schristos 	REQUIRE((target != NULL && ISC_BUFFER_VALID(target)) ||
20719742fdb4Schristos 		(target == NULL && name != NULL &&
20729742fdb4Schristos 		 ISC_BUFFER_VALID(name->buffer)));
20739742fdb4Schristos 	if (prefix == NULL || prefix->labels == 0) {
2074f2e20987Schristos 		copy_prefix = false;
20759742fdb4Schristos 	}
20769742fdb4Schristos 	if (suffix == NULL || suffix->labels == 0) {
2077f2e20987Schristos 		copy_suffix = false;
20789742fdb4Schristos 	}
20799742fdb4Schristos 	if (copy_prefix && (prefix->attributes & DNS_NAMEATTR_ABSOLUTE) != 0) {
2080f2e20987Schristos 		absolute = true;
2081e2b1b9c0Schristos 		REQUIRE(!copy_suffix);
2082e2b1b9c0Schristos 	}
2083e2b1b9c0Schristos 	if (name == NULL) {
2084e2b1b9c0Schristos 		DNS_NAME_INIT(&tmp_name, odata);
2085e2b1b9c0Schristos 		name = &tmp_name;
2086e2b1b9c0Schristos 	}
2087e2b1b9c0Schristos 	if (target == NULL) {
2088e2b1b9c0Schristos 		INSIST(name->buffer != NULL);
2089e2b1b9c0Schristos 		target = name->buffer;
2090e2b1b9c0Schristos 		isc_buffer_clear(name->buffer);
2091e2b1b9c0Schristos 	}
2092e2b1b9c0Schristos 
2093e2b1b9c0Schristos 	REQUIRE(BINDABLE(name));
2094e2b1b9c0Schristos 
2095e2b1b9c0Schristos 	/*
2096e2b1b9c0Schristos 	 * Set up.
2097e2b1b9c0Schristos 	 */
2098e2b1b9c0Schristos 	nrem = target->length - target->used;
2099e2b1b9c0Schristos 	ndata = (unsigned char *)target->base + target->used;
21009742fdb4Schristos 	if (nrem > DNS_NAME_MAXWIRE) {
2101e2b1b9c0Schristos 		nrem = DNS_NAME_MAXWIRE;
21029742fdb4Schristos 	}
2103e2b1b9c0Schristos 	length = 0;
2104e2b1b9c0Schristos 	prefix_length = 0;
2105e2b1b9c0Schristos 	labels = 0;
2106e2b1b9c0Schristos 	if (copy_prefix) {
2107e2b1b9c0Schristos 		prefix_length = prefix->length;
2108e2b1b9c0Schristos 		length += prefix_length;
2109e2b1b9c0Schristos 		labels += prefix->labels;
2110e2b1b9c0Schristos 	}
2111e2b1b9c0Schristos 	if (copy_suffix) {
2112e2b1b9c0Schristos 		length += suffix->length;
2113e2b1b9c0Schristos 		labels += suffix->labels;
2114e2b1b9c0Schristos 	}
2115e2b1b9c0Schristos 	if (length > DNS_NAME_MAXWIRE) {
2116e2b1b9c0Schristos 		MAKE_EMPTY(name);
2117e2b1b9c0Schristos 		return (DNS_R_NAMETOOLONG);
2118e2b1b9c0Schristos 	}
2119e2b1b9c0Schristos 	if (length > nrem) {
2120e2b1b9c0Schristos 		MAKE_EMPTY(name);
2121e2b1b9c0Schristos 		return (ISC_R_NOSPACE);
2122e2b1b9c0Schristos 	}
2123e2b1b9c0Schristos 
2124e2b1b9c0Schristos 	if (copy_suffix) {
21259742fdb4Schristos 		if ((suffix->attributes & DNS_NAMEATTR_ABSOLUTE) != 0) {
2126f2e20987Schristos 			absolute = true;
21279742fdb4Schristos 		}
2128e2b1b9c0Schristos 		memmove(ndata + prefix_length, suffix->ndata, suffix->length);
2129e2b1b9c0Schristos 	}
2130e2b1b9c0Schristos 
2131e2b1b9c0Schristos 	/*
2132e2b1b9c0Schristos 	 * If 'prefix' and 'name' are the same object, and the object has
2133e2b1b9c0Schristos 	 * a dedicated buffer, and we're using it, then we don't have to
2134e2b1b9c0Schristos 	 * copy anything.
2135e2b1b9c0Schristos 	 */
21369742fdb4Schristos 	if (copy_prefix && (prefix != name || prefix->buffer != target)) {
2137e2b1b9c0Schristos 		memmove(ndata, prefix->ndata, prefix_length);
21389742fdb4Schristos 	}
2139e2b1b9c0Schristos 
2140e2b1b9c0Schristos 	name->ndata = ndata;
2141e2b1b9c0Schristos 	name->labels = labels;
2142e2b1b9c0Schristos 	name->length = length;
21439742fdb4Schristos 	if (absolute) {
2144e2b1b9c0Schristos 		name->attributes = DNS_NAMEATTR_ABSOLUTE;
21459742fdb4Schristos 	} else {
2146e2b1b9c0Schristos 		name->attributes = 0;
21479742fdb4Schristos 	}
2148e2b1b9c0Schristos 
2149e2b1b9c0Schristos 	if (name->labels > 0 && name->offsets != NULL) {
2150e2b1b9c0Schristos 		INIT_OFFSETS(name, offsets, odata);
2151e2b1b9c0Schristos 		set_offsets(name, offsets, NULL);
2152e2b1b9c0Schristos 	}
2153e2b1b9c0Schristos 
2154e2b1b9c0Schristos 	isc_buffer_add(target, name->length);
2155e2b1b9c0Schristos 
2156e2b1b9c0Schristos 	return (ISC_R_SUCCESS);
2157e2b1b9c0Schristos }
2158e2b1b9c0Schristos 
2159e2b1b9c0Schristos void
dns_name_split(const dns_name_t * name,unsigned int suffixlabels,dns_name_t * prefix,dns_name_t * suffix)2160e2b1b9c0Schristos dns_name_split(const dns_name_t *name, unsigned int suffixlabels,
2161e2b1b9c0Schristos 	       dns_name_t *prefix, dns_name_t *suffix)
2162e2b1b9c0Schristos 
2163e2b1b9c0Schristos {
2164e2b1b9c0Schristos 	unsigned int splitlabel;
2165e2b1b9c0Schristos 
2166e2b1b9c0Schristos 	REQUIRE(VALID_NAME(name));
2167e2b1b9c0Schristos 	REQUIRE(suffixlabels > 0);
2168e2b1b9c0Schristos 	REQUIRE(suffixlabels <= name->labels);
2169e2b1b9c0Schristos 	REQUIRE(prefix != NULL || suffix != NULL);
21709742fdb4Schristos 	REQUIRE(prefix == NULL || (VALID_NAME(prefix) && BINDABLE(prefix)));
21719742fdb4Schristos 	REQUIRE(suffix == NULL || (VALID_NAME(suffix) && BINDABLE(suffix)));
2172e2b1b9c0Schristos 
2173e2b1b9c0Schristos 	splitlabel = name->labels - suffixlabels;
2174e2b1b9c0Schristos 
21759742fdb4Schristos 	if (prefix != NULL) {
2176e2b1b9c0Schristos 		dns_name_getlabelsequence(name, 0, splitlabel, prefix);
21779742fdb4Schristos 	}
2178e2b1b9c0Schristos 
21799742fdb4Schristos 	if (suffix != NULL) {
21809742fdb4Schristos 		dns_name_getlabelsequence(name, splitlabel, suffixlabels,
21819742fdb4Schristos 					  suffix);
21829742fdb4Schristos 	}
2183e2b1b9c0Schristos 
2184e2b1b9c0Schristos 	return;
2185e2b1b9c0Schristos }
2186e2b1b9c0Schristos 
21879742fdb4Schristos void
dns_name_dup(const dns_name_t * source,isc_mem_t * mctx,dns_name_t * target)21889742fdb4Schristos dns_name_dup(const dns_name_t *source, isc_mem_t *mctx, dns_name_t *target) {
2189e2b1b9c0Schristos 	/*
2190e2b1b9c0Schristos 	 * Make 'target' a dynamically allocated copy of 'source'.
2191e2b1b9c0Schristos 	 */
2192e2b1b9c0Schristos 
2193e2b1b9c0Schristos 	REQUIRE(VALID_NAME(source));
2194e2b1b9c0Schristos 	REQUIRE(source->length > 0);
2195e2b1b9c0Schristos 	REQUIRE(VALID_NAME(target));
2196e2b1b9c0Schristos 	REQUIRE(BINDABLE(target));
2197e2b1b9c0Schristos 
2198e2b1b9c0Schristos 	/*
2199e2b1b9c0Schristos 	 * Make 'target' empty in case of failure.
2200e2b1b9c0Schristos 	 */
2201e2b1b9c0Schristos 	MAKE_EMPTY(target);
2202e2b1b9c0Schristos 
2203e2b1b9c0Schristos 	target->ndata = isc_mem_get(mctx, source->length);
2204e2b1b9c0Schristos 
2205e2b1b9c0Schristos 	memmove(target->ndata, source->ndata, source->length);
2206e2b1b9c0Schristos 
2207e2b1b9c0Schristos 	target->length = source->length;
2208e2b1b9c0Schristos 	target->labels = source->labels;
2209e2b1b9c0Schristos 	target->attributes = DNS_NAMEATTR_DYNAMIC;
22109742fdb4Schristos 	if ((source->attributes & DNS_NAMEATTR_ABSOLUTE) != 0) {
2211e2b1b9c0Schristos 		target->attributes |= DNS_NAMEATTR_ABSOLUTE;
22129742fdb4Schristos 	}
2213e2b1b9c0Schristos 	if (target->offsets != NULL) {
22149742fdb4Schristos 		if (source->offsets != NULL) {
2215e2b1b9c0Schristos 			memmove(target->offsets, source->offsets,
2216e2b1b9c0Schristos 				source->labels);
22179742fdb4Schristos 		} else {
2218e2b1b9c0Schristos 			set_offsets(target, target->offsets, NULL);
2219e2b1b9c0Schristos 		}
22209742fdb4Schristos 	}
2221e2b1b9c0Schristos }
2222e2b1b9c0Schristos 
2223e2b1b9c0Schristos isc_result_t
dns_name_dupwithoffsets(const dns_name_t * source,isc_mem_t * mctx,dns_name_t * target)2224e2b1b9c0Schristos dns_name_dupwithoffsets(const dns_name_t *source, isc_mem_t *mctx,
22259742fdb4Schristos 			dns_name_t *target) {
2226e2b1b9c0Schristos 	/*
2227e2b1b9c0Schristos 	 * Make 'target' a read-only dynamically allocated copy of 'source'.
2228e2b1b9c0Schristos 	 * 'target' will also have a dynamically allocated offsets table.
2229e2b1b9c0Schristos 	 */
2230e2b1b9c0Schristos 
2231e2b1b9c0Schristos 	REQUIRE(VALID_NAME(source));
2232e2b1b9c0Schristos 	REQUIRE(source->length > 0);
2233e2b1b9c0Schristos 	REQUIRE(VALID_NAME(target));
2234e2b1b9c0Schristos 	REQUIRE(BINDABLE(target));
2235e2b1b9c0Schristos 	REQUIRE(target->offsets == NULL);
2236e2b1b9c0Schristos 
2237e2b1b9c0Schristos 	/*
2238e2b1b9c0Schristos 	 * Make 'target' empty in case of failure.
2239e2b1b9c0Schristos 	 */
2240e2b1b9c0Schristos 	MAKE_EMPTY(target);
2241e2b1b9c0Schristos 
2242e2b1b9c0Schristos 	target->ndata = isc_mem_get(mctx, source->length + source->labels);
2243e2b1b9c0Schristos 
2244e2b1b9c0Schristos 	memmove(target->ndata, source->ndata, source->length);
2245e2b1b9c0Schristos 
2246e2b1b9c0Schristos 	target->length = source->length;
2247e2b1b9c0Schristos 	target->labels = source->labels;
2248e2b1b9c0Schristos 	target->attributes = DNS_NAMEATTR_DYNAMIC | DNS_NAMEATTR_DYNOFFSETS |
2249e2b1b9c0Schristos 			     DNS_NAMEATTR_READONLY;
22509742fdb4Schristos 	if ((source->attributes & DNS_NAMEATTR_ABSOLUTE) != 0) {
2251e2b1b9c0Schristos 		target->attributes |= DNS_NAMEATTR_ABSOLUTE;
22529742fdb4Schristos 	}
2253e2b1b9c0Schristos 	target->offsets = target->ndata + source->length;
22549742fdb4Schristos 	if (source->offsets != NULL) {
2255e2b1b9c0Schristos 		memmove(target->offsets, source->offsets, source->labels);
22569742fdb4Schristos 	} else {
2257e2b1b9c0Schristos 		set_offsets(target, target->offsets, NULL);
22589742fdb4Schristos 	}
2259e2b1b9c0Schristos 
2260e2b1b9c0Schristos 	return (ISC_R_SUCCESS);
2261e2b1b9c0Schristos }
2262e2b1b9c0Schristos 
2263e2b1b9c0Schristos void
dns_name_free(dns_name_t * name,isc_mem_t * mctx)2264e2b1b9c0Schristos dns_name_free(dns_name_t *name, isc_mem_t *mctx) {
2265e2b1b9c0Schristos 	size_t size;
2266e2b1b9c0Schristos 
2267e2b1b9c0Schristos 	/*
2268e2b1b9c0Schristos 	 * Free 'name'.
2269e2b1b9c0Schristos 	 */
2270e2b1b9c0Schristos 
2271e2b1b9c0Schristos 	REQUIRE(VALID_NAME(name));
2272e2b1b9c0Schristos 	REQUIRE((name->attributes & DNS_NAMEATTR_DYNAMIC) != 0);
2273e2b1b9c0Schristos 
2274e2b1b9c0Schristos 	size = name->length;
22759742fdb4Schristos 	if ((name->attributes & DNS_NAMEATTR_DYNOFFSETS) != 0) {
2276e2b1b9c0Schristos 		size += name->labels;
22779742fdb4Schristos 	}
2278e2b1b9c0Schristos 	isc_mem_put(mctx, name->ndata, size);
2279e2b1b9c0Schristos 	dns_name_invalidate(name);
2280e2b1b9c0Schristos }
2281e2b1b9c0Schristos 
2282e2b1b9c0Schristos isc_result_t
dns_name_digest(const dns_name_t * name,dns_digestfunc_t digest,void * arg)2283e2b1b9c0Schristos dns_name_digest(const dns_name_t *name, dns_digestfunc_t digest, void *arg) {
2284e2b1b9c0Schristos 	dns_name_t downname;
2285e2b1b9c0Schristos 	unsigned char data[256];
2286e2b1b9c0Schristos 	isc_buffer_t buffer;
2287e2b1b9c0Schristos 	isc_result_t result;
2288e2b1b9c0Schristos 	isc_region_t r;
2289e2b1b9c0Schristos 
2290e2b1b9c0Schristos 	/*
2291e2b1b9c0Schristos 	 * Send 'name' in DNSSEC canonical form to 'digest'.
2292e2b1b9c0Schristos 	 */
2293e2b1b9c0Schristos 
2294e2b1b9c0Schristos 	REQUIRE(VALID_NAME(name));
2295e2b1b9c0Schristos 	REQUIRE(digest != NULL);
2296e2b1b9c0Schristos 
2297e2b1b9c0Schristos 	DNS_NAME_INIT(&downname, NULL);
2298e2b1b9c0Schristos 
2299e2b1b9c0Schristos 	isc_buffer_init(&buffer, data, sizeof(data));
2300e2b1b9c0Schristos 
2301e2b1b9c0Schristos 	result = dns_name_downcase(name, &downname, &buffer);
23029742fdb4Schristos 	if (result != ISC_R_SUCCESS) {
2303e2b1b9c0Schristos 		return (result);
23049742fdb4Schristos 	}
2305e2b1b9c0Schristos 
2306e2b1b9c0Schristos 	isc_buffer_usedregion(&buffer, &r);
2307e2b1b9c0Schristos 
2308e2b1b9c0Schristos 	return ((digest)(arg, &r));
2309e2b1b9c0Schristos }
2310e2b1b9c0Schristos 
2311f2e20987Schristos bool
dns_name_dynamic(const dns_name_t * name)2312e2b1b9c0Schristos dns_name_dynamic(const dns_name_t *name) {
2313e2b1b9c0Schristos 	REQUIRE(VALID_NAME(name));
2314e2b1b9c0Schristos 
2315e2b1b9c0Schristos 	/*
2316e2b1b9c0Schristos 	 * Returns whether there is dynamic memory associated with this name.
2317e2b1b9c0Schristos 	 */
2318e2b1b9c0Schristos 
23199742fdb4Schristos 	return ((name->attributes & DNS_NAMEATTR_DYNAMIC) != 0 ? true : false);
2320e2b1b9c0Schristos }
2321e2b1b9c0Schristos 
2322e2b1b9c0Schristos isc_result_t
dns_name_print(const dns_name_t * name,FILE * stream)2323e2b1b9c0Schristos dns_name_print(const dns_name_t *name, FILE *stream) {
2324e2b1b9c0Schristos 	isc_result_t result;
2325e2b1b9c0Schristos 	isc_buffer_t b;
2326e2b1b9c0Schristos 	isc_region_t r;
2327e2b1b9c0Schristos 	char t[1024];
2328e2b1b9c0Schristos 
2329e2b1b9c0Schristos 	/*
2330e2b1b9c0Schristos 	 * Print 'name' on 'stream'.
2331e2b1b9c0Schristos 	 */
2332e2b1b9c0Schristos 
2333e2b1b9c0Schristos 	REQUIRE(VALID_NAME(name));
2334e2b1b9c0Schristos 
2335e2b1b9c0Schristos 	isc_buffer_init(&b, t, sizeof(t));
2336f2e20987Schristos 	result = dns_name_totext(name, false, &b);
23379742fdb4Schristos 	if (result != ISC_R_SUCCESS) {
2338e2b1b9c0Schristos 		return (result);
23399742fdb4Schristos 	}
2340e2b1b9c0Schristos 	isc_buffer_usedregion(&b, &r);
2341e2b1b9c0Schristos 	fprintf(stream, "%.*s", (int)r.length, (char *)r.base);
2342e2b1b9c0Schristos 
2343e2b1b9c0Schristos 	return (ISC_R_SUCCESS);
2344e2b1b9c0Schristos }
2345e2b1b9c0Schristos 
2346e2b1b9c0Schristos isc_result_t
dns_name_settotextfilter(dns_name_totextfilter_t * proc)23479742fdb4Schristos dns_name_settotextfilter(dns_name_totextfilter_t *proc) {
2348e2b1b9c0Schristos 	/*
2349e2b1b9c0Schristos 	 * If we already have been here set / clear as appropriate.
2350e2b1b9c0Schristos 	 */
23519742fdb4Schristos 	if (totext_filter_proc != NULL && proc != NULL) {
23529742fdb4Schristos 		if (totext_filter_proc == proc) {
2353e2b1b9c0Schristos 			return (ISC_R_SUCCESS);
2354e2b1b9c0Schristos 		}
23559742fdb4Schristos 	}
23569742fdb4Schristos 	if (proc == NULL && totext_filter_proc != NULL) {
23579742fdb4Schristos 		totext_filter_proc = NULL;
23589742fdb4Schristos 		return (ISC_R_SUCCESS);
2359e2b1b9c0Schristos 	}
2360e2b1b9c0Schristos 
23619742fdb4Schristos 	totext_filter_proc = proc;
23629742fdb4Schristos 
23639742fdb4Schristos 	return (ISC_R_SUCCESS);
2364e2b1b9c0Schristos }
2365e2b1b9c0Schristos 
2366e2b1b9c0Schristos void
dns_name_format(const dns_name_t * name,char * cp,unsigned int size)2367e2b1b9c0Schristos dns_name_format(const dns_name_t *name, char *cp, unsigned int size) {
2368e2b1b9c0Schristos 	isc_result_t result;
2369e2b1b9c0Schristos 	isc_buffer_t buf;
2370e2b1b9c0Schristos 
2371e2b1b9c0Schristos 	REQUIRE(size > 0);
2372e2b1b9c0Schristos 
2373e2b1b9c0Schristos 	/*
2374e2b1b9c0Schristos 	 * Leave room for null termination after buffer.
2375e2b1b9c0Schristos 	 */
2376e2b1b9c0Schristos 	isc_buffer_init(&buf, cp, size - 1);
2377f2e20987Schristos 	result = dns_name_totext(name, true, &buf);
2378e2b1b9c0Schristos 	if (result == ISC_R_SUCCESS) {
237955ba2b39Schristos 		isc_buffer_putuint8(&buf, (uint8_t)'\0');
238055ba2b39Schristos 	} else {
2381e2b1b9c0Schristos 		snprintf(cp, size, "<unknown>");
2382e2b1b9c0Schristos 	}
238355ba2b39Schristos }
2384e2b1b9c0Schristos 
2385e2b1b9c0Schristos /*
2386e2b1b9c0Schristos  * dns_name_tostring() -- similar to dns_name_format() but allocates its own
2387e2b1b9c0Schristos  * memory.
2388e2b1b9c0Schristos  */
2389e2b1b9c0Schristos isc_result_t
dns_name_tostring(const dns_name_t * name,char ** target,isc_mem_t * mctx)2390e2b1b9c0Schristos dns_name_tostring(const dns_name_t *name, char **target, isc_mem_t *mctx) {
2391e2b1b9c0Schristos 	isc_result_t result;
2392e2b1b9c0Schristos 	isc_buffer_t buf;
2393e2b1b9c0Schristos 	isc_region_t reg;
2394e2b1b9c0Schristos 	char *p, txt[DNS_NAME_FORMATSIZE];
2395e2b1b9c0Schristos 
2396e2b1b9c0Schristos 	REQUIRE(VALID_NAME(name));
2397e2b1b9c0Schristos 	REQUIRE(target != NULL && *target == NULL);
2398e2b1b9c0Schristos 
2399e2b1b9c0Schristos 	isc_buffer_init(&buf, txt, sizeof(txt));
2400f2e20987Schristos 	result = dns_name_totext(name, false, &buf);
24019742fdb4Schristos 	if (result != ISC_R_SUCCESS) {
2402e2b1b9c0Schristos 		return (result);
24039742fdb4Schristos 	}
2404e2b1b9c0Schristos 
2405e2b1b9c0Schristos 	isc_buffer_usedregion(&buf, &reg);
2406e2b1b9c0Schristos 	p = isc_mem_allocate(mctx, reg.length + 1);
2407e2b1b9c0Schristos 	memmove(p, (char *)reg.base, (int)reg.length);
2408e2b1b9c0Schristos 	p[reg.length] = '\0';
2409e2b1b9c0Schristos 
2410e2b1b9c0Schristos 	*target = p;
2411e2b1b9c0Schristos 	return (ISC_R_SUCCESS);
2412e2b1b9c0Schristos }
2413e2b1b9c0Schristos 
2414e2b1b9c0Schristos /*
2415e2b1b9c0Schristos  * dns_name_fromstring() -- convert directly from a string to a name,
2416e2b1b9c0Schristos  * allocating memory as needed
2417e2b1b9c0Schristos  */
2418e2b1b9c0Schristos isc_result_t
dns_name_fromstring(dns_name_t * target,const char * src,unsigned int options,isc_mem_t * mctx)2419e2b1b9c0Schristos dns_name_fromstring(dns_name_t *target, const char *src, unsigned int options,
24209742fdb4Schristos 		    isc_mem_t *mctx) {
2421e2b1b9c0Schristos 	return (dns_name_fromstring2(target, src, dns_rootname, options, mctx));
2422e2b1b9c0Schristos }
2423e2b1b9c0Schristos 
2424e2b1b9c0Schristos isc_result_t
dns_name_fromstring2(dns_name_t * target,const char * src,const dns_name_t * origin,unsigned int options,isc_mem_t * mctx)2425e2b1b9c0Schristos dns_name_fromstring2(dns_name_t *target, const char *src,
2426e2b1b9c0Schristos 		     const dns_name_t *origin, unsigned int options,
24279742fdb4Schristos 		     isc_mem_t *mctx) {
2428e2b1b9c0Schristos 	isc_result_t result;
2429e2b1b9c0Schristos 	isc_buffer_t buf;
2430e2b1b9c0Schristos 	dns_fixedname_t fn;
2431e2b1b9c0Schristos 	dns_name_t *name;
2432e2b1b9c0Schristos 
2433e2b1b9c0Schristos 	REQUIRE(src != NULL);
2434e2b1b9c0Schristos 
2435e2b1b9c0Schristos 	isc_buffer_constinit(&buf, src, strlen(src));
2436e2b1b9c0Schristos 	isc_buffer_add(&buf, strlen(src));
24379742fdb4Schristos 	if (BINDABLE(target) && target->buffer != NULL) {
2438e2b1b9c0Schristos 		name = target;
24399742fdb4Schristos 	} else {
2440e2b1b9c0Schristos 		name = dns_fixedname_initname(&fn);
2441e2b1b9c0Schristos 	}
2442e2b1b9c0Schristos 
2443e2b1b9c0Schristos 	result = dns_name_fromtext(name, &buf, origin, options, NULL);
24449742fdb4Schristos 	if (result != ISC_R_SUCCESS) {
2445e2b1b9c0Schristos 		return (result);
2446e2b1b9c0Schristos 	}
2447e2b1b9c0Schristos 
24489742fdb4Schristos 	if (name != target) {
24499742fdb4Schristos 		result = dns_name_dupwithoffsets(name, mctx, target);
24509742fdb4Schristos 	}
24519742fdb4Schristos 	return (result);
24529742fdb4Schristos }
24539742fdb4Schristos 
24549742fdb4Schristos static isc_result_t
name_copy(const dns_name_t * source,dns_name_t * dest,isc_buffer_t * target)24558b4c8a26Schristos name_copy(const dns_name_t *source, dns_name_t *dest, isc_buffer_t *target) {
2456fadf0758Schristos 	unsigned char *ndata = NULL;
2457e2b1b9c0Schristos 
2458e2b1b9c0Schristos 	/*
2459e2b1b9c0Schristos 	 * Make dest a copy of source.
2460e2b1b9c0Schristos 	 */
2461e2b1b9c0Schristos 
2462e2b1b9c0Schristos 	REQUIRE(BINDABLE(dest));
2463e2b1b9c0Schristos 
2464e2b1b9c0Schristos 	/*
2465e2b1b9c0Schristos 	 * Set up.
2466e2b1b9c0Schristos 	 */
24678b4c8a26Schristos 	if (target->length - target->used < source->length) {
2468e2b1b9c0Schristos 		return (ISC_R_NOSPACE);
24698b4c8a26Schristos 	}
2470e2b1b9c0Schristos 
2471e2b1b9c0Schristos 	ndata = (unsigned char *)target->base + target->used;
2472e2b1b9c0Schristos 	dest->ndata = target->base;
2473e2b1b9c0Schristos 
24748b4c8a26Schristos 	if (source->length != 0) {
2475e2b1b9c0Schristos 		memmove(ndata, source->ndata, source->length);
24768b4c8a26Schristos 	}
2477e2b1b9c0Schristos 
2478e2b1b9c0Schristos 	dest->ndata = ndata;
2479e2b1b9c0Schristos 	dest->labels = source->labels;
2480e2b1b9c0Schristos 	dest->length = source->length;
24818b4c8a26Schristos 	if ((source->attributes & DNS_NAMEATTR_ABSOLUTE) != 0) {
2482e2b1b9c0Schristos 		dest->attributes = DNS_NAMEATTR_ABSOLUTE;
24838b4c8a26Schristos 	} else {
2484e2b1b9c0Schristos 		dest->attributes = 0;
24858b4c8a26Schristos 	}
2486e2b1b9c0Schristos 
2487e2b1b9c0Schristos 	if (dest->labels > 0 && dest->offsets != NULL) {
2488fadf0758Schristos 		if (source->offsets != NULL && source->labels != 0) {
2489e2b1b9c0Schristos 			memmove(dest->offsets, source->offsets, source->labels);
24908b4c8a26Schristos 		} else {
2491e2b1b9c0Schristos 			set_offsets(dest, dest->offsets, NULL);
2492e2b1b9c0Schristos 		}
24938b4c8a26Schristos 	}
2494e2b1b9c0Schristos 
2495e2b1b9c0Schristos 	isc_buffer_add(target, dest->length);
2496e2b1b9c0Schristos 
2497e2b1b9c0Schristos 	return (ISC_R_SUCCESS);
2498e2b1b9c0Schristos }
2499e2b1b9c0Schristos 
25008b4c8a26Schristos isc_result_t
dns_name_copy(const dns_name_t * source,dns_name_t * dest,isc_buffer_t * target)25019742fdb4Schristos dns_name_copy(const dns_name_t *source, dns_name_t *dest,
25029742fdb4Schristos 	      isc_buffer_t *target) {
25038b4c8a26Schristos 	REQUIRE(VALID_NAME(source));
25048b4c8a26Schristos 	REQUIRE(VALID_NAME(dest));
25058b4c8a26Schristos 	REQUIRE(target != NULL);
25068b4c8a26Schristos 
25078b4c8a26Schristos 	return (name_copy(source, dest, target));
25088b4c8a26Schristos }
25098b4c8a26Schristos 
25108b4c8a26Schristos void
dns_name_copynf(const dns_name_t * source,dns_name_t * dest)25119742fdb4Schristos dns_name_copynf(const dns_name_t *source, dns_name_t *dest) {
25128b4c8a26Schristos 	REQUIRE(VALID_NAME(source));
25138b4c8a26Schristos 	REQUIRE(VALID_NAME(dest));
25148b4c8a26Schristos 	REQUIRE(dest->buffer != NULL);
25158b4c8a26Schristos 
25168b4c8a26Schristos 	isc_buffer_clear(dest->buffer);
25178b4c8a26Schristos 	RUNTIME_CHECK(name_copy(source, dest, dest->buffer) == ISC_R_SUCCESS);
25188b4c8a26Schristos }
25198b4c8a26Schristos 
2520e2b1b9c0Schristos /*
2521e2b1b9c0Schristos  * Service Discovery Prefixes RFC 6763.
2522e2b1b9c0Schristos  */
2523e2b1b9c0Schristos static unsigned char b_dns_sd_udp_data[] = "\001b\007_dns-sd\004_udp";
2524e2b1b9c0Schristos static unsigned char b_dns_sd_udp_offsets[] = { 0, 2, 10 };
2525e2b1b9c0Schristos static unsigned char db_dns_sd_udp_data[] = "\002db\007_dns-sd\004_udp";
2526e2b1b9c0Schristos static unsigned char db_dns_sd_udp_offsets[] = { 0, 3, 11 };
2527e2b1b9c0Schristos static unsigned char r_dns_sd_udp_data[] = "\001r\007_dns-sd\004_udp";
2528e2b1b9c0Schristos static unsigned char r_dns_sd_udp_offsets[] = { 0, 2, 10 };
2529e2b1b9c0Schristos static unsigned char dr_dns_sd_udp_data[] = "\002dr\007_dns-sd\004_udp";
2530e2b1b9c0Schristos static unsigned char dr_dns_sd_udp_offsets[] = { 0, 3, 11 };
2531e2b1b9c0Schristos static unsigned char lb_dns_sd_udp_data[] = "\002lb\007_dns-sd\004_udp";
2532e2b1b9c0Schristos static unsigned char lb_dns_sd_udp_offsets[] = { 0, 3, 11 };
2533e2b1b9c0Schristos 
2534e2b1b9c0Schristos static dns_name_t const dns_sd[] = {
2535e2b1b9c0Schristos 	DNS_NAME_INITNONABSOLUTE(b_dns_sd_udp_data, b_dns_sd_udp_offsets),
2536e2b1b9c0Schristos 	DNS_NAME_INITNONABSOLUTE(db_dns_sd_udp_data, db_dns_sd_udp_offsets),
2537e2b1b9c0Schristos 	DNS_NAME_INITNONABSOLUTE(r_dns_sd_udp_data, r_dns_sd_udp_offsets),
2538e2b1b9c0Schristos 	DNS_NAME_INITNONABSOLUTE(dr_dns_sd_udp_data, dr_dns_sd_udp_offsets),
2539e2b1b9c0Schristos 	DNS_NAME_INITNONABSOLUTE(lb_dns_sd_udp_data, lb_dns_sd_udp_offsets)
2540e2b1b9c0Schristos };
2541e2b1b9c0Schristos 
2542f2e20987Schristos bool
dns_name_isdnssd(const dns_name_t * name)2543e2b1b9c0Schristos dns_name_isdnssd(const dns_name_t *name) {
2544e2b1b9c0Schristos 	size_t i;
2545e2b1b9c0Schristos 	dns_name_t prefix;
2546e2b1b9c0Schristos 
2547e2b1b9c0Schristos 	if (dns_name_countlabels(name) > 3U) {
2548e2b1b9c0Schristos 		dns_name_init(&prefix, NULL);
2549e2b1b9c0Schristos 		dns_name_getlabelsequence(name, 0, 3, &prefix);
25509742fdb4Schristos 		for (i = 0; i < (sizeof(dns_sd) / sizeof(dns_sd[0])); i++) {
25519742fdb4Schristos 			if (dns_name_equal(&prefix, &dns_sd[i])) {
2552f2e20987Schristos 				return (true);
2553e2b1b9c0Schristos 			}
25549742fdb4Schristos 		}
25559742fdb4Schristos 	}
2556e2b1b9c0Schristos 
2557f2e20987Schristos 	return (false);
2558e2b1b9c0Schristos }
2559e2b1b9c0Schristos 
2560e2b1b9c0Schristos static unsigned char inaddr10_offsets[] = { 0, 3, 11, 16 };
2561e2b1b9c0Schristos static unsigned char inaddr172_offsets[] = { 0, 3, 7, 15, 20 };
2562e2b1b9c0Schristos static unsigned char inaddr192_offsets[] = { 0, 4, 8, 16, 21 };
2563e2b1b9c0Schristos 
2564e2b1b9c0Schristos static unsigned char inaddr10[] = "\00210\007IN-ADDR\004ARPA";
2565e2b1b9c0Schristos 
2566e2b1b9c0Schristos static unsigned char inaddr16172[] = "\00216\003172\007IN-ADDR\004ARPA";
2567e2b1b9c0Schristos static unsigned char inaddr17172[] = "\00217\003172\007IN-ADDR\004ARPA";
2568e2b1b9c0Schristos static unsigned char inaddr18172[] = "\00218\003172\007IN-ADDR\004ARPA";
2569e2b1b9c0Schristos static unsigned char inaddr19172[] = "\00219\003172\007IN-ADDR\004ARPA";
2570e2b1b9c0Schristos static unsigned char inaddr20172[] = "\00220\003172\007IN-ADDR\004ARPA";
2571e2b1b9c0Schristos static unsigned char inaddr21172[] = "\00221\003172\007IN-ADDR\004ARPA";
2572e2b1b9c0Schristos static unsigned char inaddr22172[] = "\00222\003172\007IN-ADDR\004ARPA";
2573e2b1b9c0Schristos static unsigned char inaddr23172[] = "\00223\003172\007IN-ADDR\004ARPA";
2574e2b1b9c0Schristos static unsigned char inaddr24172[] = "\00224\003172\007IN-ADDR\004ARPA";
2575e2b1b9c0Schristos static unsigned char inaddr25172[] = "\00225\003172\007IN-ADDR\004ARPA";
2576e2b1b9c0Schristos static unsigned char inaddr26172[] = "\00226\003172\007IN-ADDR\004ARPA";
2577e2b1b9c0Schristos static unsigned char inaddr27172[] = "\00227\003172\007IN-ADDR\004ARPA";
2578e2b1b9c0Schristos static unsigned char inaddr28172[] = "\00228\003172\007IN-ADDR\004ARPA";
2579e2b1b9c0Schristos static unsigned char inaddr29172[] = "\00229\003172\007IN-ADDR\004ARPA";
2580e2b1b9c0Schristos static unsigned char inaddr30172[] = "\00230\003172\007IN-ADDR\004ARPA";
2581e2b1b9c0Schristos static unsigned char inaddr31172[] = "\00231\003172\007IN-ADDR\004ARPA";
2582e2b1b9c0Schristos 
2583e2b1b9c0Schristos static unsigned char inaddr168192[] = "\003168\003192\007IN-ADDR\004ARPA";
2584e2b1b9c0Schristos 
2585e2b1b9c0Schristos static dns_name_t const rfc1918names[] = {
2586e2b1b9c0Schristos 	DNS_NAME_INITABSOLUTE(inaddr10, inaddr10_offsets),
2587e2b1b9c0Schristos 	DNS_NAME_INITABSOLUTE(inaddr16172, inaddr172_offsets),
2588e2b1b9c0Schristos 	DNS_NAME_INITABSOLUTE(inaddr17172, inaddr172_offsets),
2589e2b1b9c0Schristos 	DNS_NAME_INITABSOLUTE(inaddr18172, inaddr172_offsets),
2590e2b1b9c0Schristos 	DNS_NAME_INITABSOLUTE(inaddr19172, inaddr172_offsets),
2591e2b1b9c0Schristos 	DNS_NAME_INITABSOLUTE(inaddr20172, inaddr172_offsets),
2592e2b1b9c0Schristos 	DNS_NAME_INITABSOLUTE(inaddr21172, inaddr172_offsets),
2593e2b1b9c0Schristos 	DNS_NAME_INITABSOLUTE(inaddr22172, inaddr172_offsets),
2594e2b1b9c0Schristos 	DNS_NAME_INITABSOLUTE(inaddr23172, inaddr172_offsets),
2595e2b1b9c0Schristos 	DNS_NAME_INITABSOLUTE(inaddr24172, inaddr172_offsets),
2596e2b1b9c0Schristos 	DNS_NAME_INITABSOLUTE(inaddr25172, inaddr172_offsets),
2597e2b1b9c0Schristos 	DNS_NAME_INITABSOLUTE(inaddr26172, inaddr172_offsets),
2598e2b1b9c0Schristos 	DNS_NAME_INITABSOLUTE(inaddr27172, inaddr172_offsets),
2599e2b1b9c0Schristos 	DNS_NAME_INITABSOLUTE(inaddr28172, inaddr172_offsets),
2600e2b1b9c0Schristos 	DNS_NAME_INITABSOLUTE(inaddr29172, inaddr172_offsets),
2601e2b1b9c0Schristos 	DNS_NAME_INITABSOLUTE(inaddr30172, inaddr172_offsets),
2602e2b1b9c0Schristos 	DNS_NAME_INITABSOLUTE(inaddr31172, inaddr172_offsets),
2603e2b1b9c0Schristos 	DNS_NAME_INITABSOLUTE(inaddr168192, inaddr192_offsets)
2604e2b1b9c0Schristos };
2605e2b1b9c0Schristos 
2606f2e20987Schristos bool
dns_name_isrfc1918(const dns_name_t * name)2607e2b1b9c0Schristos dns_name_isrfc1918(const dns_name_t *name) {
2608e2b1b9c0Schristos 	size_t i;
2609e2b1b9c0Schristos 
26109742fdb4Schristos 	for (i = 0; i < (sizeof(rfc1918names) / sizeof(*rfc1918names)); i++) {
26119742fdb4Schristos 		if (dns_name_issubdomain(name, &rfc1918names[i])) {
2612f2e20987Schristos 			return (true);
26139742fdb4Schristos 		}
26149742fdb4Schristos 	}
2615f2e20987Schristos 	return (false);
2616e2b1b9c0Schristos }
2617e2b1b9c0Schristos 
2618e2b1b9c0Schristos static unsigned char ulaoffsets[] = { 0, 2, 4, 8, 13 };
2619e2b1b9c0Schristos static unsigned char ip6fc[] = "\001c\001f\003ip6\004ARPA";
2620e2b1b9c0Schristos static unsigned char ip6fd[] = "\001d\001f\003ip6\004ARPA";
2621e2b1b9c0Schristos 
26229742fdb4Schristos static dns_name_t const ulanames[] = { DNS_NAME_INITABSOLUTE(ip6fc, ulaoffsets),
26239742fdb4Schristos 				       DNS_NAME_INITABSOLUTE(ip6fd,
26249742fdb4Schristos 							     ulaoffsets) };
2625e2b1b9c0Schristos 
2626f2e20987Schristos bool
dns_name_isula(const dns_name_t * name)2627e2b1b9c0Schristos dns_name_isula(const dns_name_t *name) {
2628e2b1b9c0Schristos 	size_t i;
2629e2b1b9c0Schristos 
26309742fdb4Schristos 	for (i = 0; i < (sizeof(ulanames) / sizeof(*ulanames)); i++) {
26319742fdb4Schristos 		if (dns_name_issubdomain(name, &ulanames[i])) {
2632f2e20987Schristos 			return (true);
26339742fdb4Schristos 		}
26349742fdb4Schristos 	}
2635f2e20987Schristos 	return (false);
2636e2b1b9c0Schristos }
2637e2b1b9c0Schristos 
2638e2b1b9c0Schristos /*
2639e2b1b9c0Schristos  * Use a simple table as we don't want all the locale stuff
2640e2b1b9c0Schristos  * associated with ishexdigit().
2641e2b1b9c0Schristos  */
26429742fdb4Schristos const char ishex[256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2643e2b1b9c0Schristos 			  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2644e2b1b9c0Schristos 			  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2645e2b1b9c0Schristos 			  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
2646e2b1b9c0Schristos 			  0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2647e2b1b9c0Schristos 			  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2648e2b1b9c0Schristos 			  0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
26499742fdb4Schristos 			  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
2650e2b1b9c0Schristos 
2651f2e20987Schristos bool
dns_name_istat(const dns_name_t * name)2652e2b1b9c0Schristos dns_name_istat(const dns_name_t *name) {
2653e2b1b9c0Schristos 	unsigned char len;
2654e2b1b9c0Schristos 	const unsigned char *ndata;
2655e2b1b9c0Schristos 
2656e2b1b9c0Schristos 	REQUIRE(VALID_NAME(name));
2657e2b1b9c0Schristos 
26589742fdb4Schristos 	if (name->labels < 1) {
2659f2e20987Schristos 		return (false);
26609742fdb4Schristos 	}
2661e2b1b9c0Schristos 
2662e2b1b9c0Schristos 	ndata = name->ndata;
2663e2b1b9c0Schristos 	len = ndata[0];
2664e2b1b9c0Schristos 	INSIST(len <= name->length);
2665e2b1b9c0Schristos 	ndata++;
2666e2b1b9c0Schristos 
2667e2b1b9c0Schristos 	/*
2668e2b1b9c0Schristos 	 * Is there at least one trust anchor reported and is the
2669f2e20987Schristos 	 * label length consistent with a trust-anchor-telemetry label.
2670e2b1b9c0Schristos 	 */
2671e2b1b9c0Schristos 	if ((len < 8) || (len - 3) % 5 != 0) {
2672f2e20987Schristos 		return (false);
2673e2b1b9c0Schristos 	}
2674e2b1b9c0Schristos 
26759742fdb4Schristos 	if (ndata[0] != '_' || maptolower[ndata[1]] != 't' ||
26769742fdb4Schristos 	    maptolower[ndata[2]] != 'a')
26779742fdb4Schristos 	{
2678f2e20987Schristos 		return (false);
2679e2b1b9c0Schristos 	}
2680e2b1b9c0Schristos 	ndata += 3;
2681e2b1b9c0Schristos 	len -= 3;
2682e2b1b9c0Schristos 
2683e2b1b9c0Schristos 	while (len > 0) {
2684e2b1b9c0Schristos 		INSIST(len >= 5);
2685e2b1b9c0Schristos 		if (ndata[0] != '-' || !ishex[ndata[1]] || !ishex[ndata[2]] ||
26869742fdb4Schristos 		    !ishex[ndata[3]] || !ishex[ndata[4]])
26879742fdb4Schristos 		{
2688f2e20987Schristos 			return (false);
2689e2b1b9c0Schristos 		}
2690e2b1b9c0Schristos 		ndata += 5;
2691e2b1b9c0Schristos 		len -= 5;
2692e2b1b9c0Schristos 	}
2693f2e20987Schristos 	return (true);
2694e2b1b9c0Schristos }
2695