xref: /openbsd/usr.bin/dig/lib/dns/name.c (revision 097a140d)
1 /*
2  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3  *
4  * Permission to use, copy, modify, and/or distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
9  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
10  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
11  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
12  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
13  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
14  * PERFORMANCE OF THIS SOFTWARE.
15  */
16 
17 /* $Id: name.c,v 1.14 2020/09/14 08:40:43 florian Exp $ */
18 
19 /*! \file */
20 #include <ctype.h>
21 #include <stdlib.h>
22 #include <isc/buffer.h>
23 #include <isc/hash.h>
24 
25 #include <string.h>
26 #include <isc/util.h>
27 
28 #include <dns/compress.h>
29 #include <dns/fixedname.h>
30 #include <dns/name.h>
31 #include <dns/result.h>
32 
33 typedef enum {
34 	ft_init = 0,
35 	ft_start,
36 	ft_ordinary,
37 	ft_initialescape,
38 	ft_escape,
39 	ft_escdecimal,
40 	ft_at
41 } ft_state;
42 
43 typedef enum {
44 	fw_start = 0,
45 	fw_ordinary,
46 	fw_newcurrent
47 } fw_state;
48 
49 static char digitvalue[256] = {
50 	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,	/*16*/
51 	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*32*/
52 	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*48*/
53 	 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, -1, -1, -1, -1, -1, -1, /*64*/
54 	-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*80*/
55 	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*96*/
56 	-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*112*/
57 	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*128*/
58 	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
59 	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
60 	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
61 	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
62 	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
63 	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
64 	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
65 	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*256*/
66 };
67 
68 static unsigned char maptolower[] = {
69 	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
70 	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
71 	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
72 	0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
73 	0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
74 	0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
75 	0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
76 	0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
77 	0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
78 	0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
79 	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
80 	0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
81 	0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
82 	0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
83 	0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
84 	0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
85 	0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
86 	0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
87 	0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
88 	0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
89 	0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
90 	0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
91 	0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
92 	0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
93 	0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
94 	0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
95 	0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
96 	0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
97 	0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
98 	0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
99 	0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
100 	0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
101 };
102 
103 #define CONVERTTOASCII(c)
104 #define CONVERTFROMASCII(c)
105 
106 #define INIT_OFFSETS(name, var, default_offsets) \
107 	if ((name)->offsets != NULL)		 \
108 		var = (name)->offsets;		 \
109 	else \
110 		var = (default_offsets);
111 
112 #define SETUP_OFFSETS(name, var, default_offsets) \
113 	if ((name)->offsets != NULL)		  \
114 		var = (name)->offsets;		  \
115 	else { \
116 		var = (default_offsets);      \
117 		set_offsets(name, var, NULL); \
118 	}
119 
120 /*%
121  * Note:  If additional attributes are added that should not be set for
122  *	  empty names, MAKE_EMPTY() must be changed so it clears them.
123  */
124 #define MAKE_EMPTY(name) \
125 do { \
126 	name->ndata = NULL; \
127 	name->length = 0; \
128 	name->labels = 0; \
129 	name->attributes &= ~DNS_NAMEATTR_ABSOLUTE; \
130 } while (0);
131 
132 /*%
133  * A name is "bindable" if it can be set to point to a new value, i.e.
134  * name->ndata and name->length may be changed.
135  */
136 #define BINDABLE(name) \
137 	((name->attributes & (DNS_NAMEATTR_READONLY|DNS_NAMEATTR_DYNAMIC)) \
138 	 == 0)
139 
140 /*%
141  * Note that the name data must be a char array, not a string
142  * literal, to avoid compiler warnings about discarding
143  * the const attribute of a string.
144  */
145 static unsigned char root_ndata[] = { "" };
146 static unsigned char root_offsets[] = { 0 };
147 
148 static dns_name_t root = DNS_NAME_INITABSOLUTE(root_ndata, root_offsets);
149 
150 /* XXXDCL make const? */
151 dns_name_t *dns_rootname = &root;
152 
153 static void
154 set_offsets(const dns_name_t *name, unsigned char *offsets,
155 	    dns_name_t *set_name);
156 
157 void
158 dns_name_init(dns_name_t *name, unsigned char *offsets) {
159 	/*
160 	 * Initialize 'name'.
161 	 */
162 	name->ndata = NULL;
163 	name->length = 0;
164 	name->labels = 0;
165 	name->attributes = 0;
166 	name->offsets = offsets;
167 	name->buffer = NULL;
168 	ISC_LINK_INIT(name, link);
169 	ISC_LIST_INIT(name->list);
170 
171 }
172 
173 void
174 dns_name_reset(dns_name_t *name) {
175 	REQUIRE(BINDABLE(name));
176 
177 	name->ndata = NULL;
178 	name->length = 0;
179 	name->labels = 0;
180 	name->attributes &= ~DNS_NAMEATTR_ABSOLUTE;
181 	if (name->buffer != NULL)
182 		isc_buffer_clear(name->buffer);
183 }
184 
185 void
186 dns_name_invalidate(dns_name_t *name) {
187 	/*
188 	 * Make 'name' invalid.
189 	 */
190 
191 	name->ndata = NULL;
192 	name->length = 0;
193 	name->labels = 0;
194 	name->attributes = 0;
195 	name->offsets = NULL;
196 	name->buffer = NULL;
197 	ISC_LINK_INIT(name, link);
198 }
199 
200 void
201 dns_name_setbuffer(dns_name_t *name, isc_buffer_t *buffer) {
202 	/*
203 	 * Dedicate a buffer for use with 'name'.
204 	 */
205 
206 	REQUIRE((buffer != NULL && name->buffer == NULL) ||
207 		(buffer == NULL));
208 
209 	name->buffer = buffer;
210 }
211 
212 int
213 dns_name_isabsolute(const dns_name_t *name) {
214 
215 	/*
216 	 * Does 'name' end in the root label?
217 	 */
218 
219 	if ((name->attributes & DNS_NAMEATTR_ABSOLUTE) != 0)
220 		return (1);
221 	return (0);
222 }
223 
224 unsigned int
225 dns_name_hash(dns_name_t *name, int case_sensitive) {
226 	unsigned int length;
227 
228 	/*
229 	 * Provide a hash value for 'name'.
230 	 */
231 
232 	if (name->labels == 0)
233 		return (0);
234 
235 	length = name->length;
236 	if (length > 16)
237 		length = 16;
238 
239 	return (isc_hash_function_reverse(name->ndata, length,
240 					  case_sensitive, NULL));
241 }
242 
243 dns_namereln_t
244 dns_name_fullcompare(const dns_name_t *name1, const dns_name_t *name2,
245 		     int *orderp, unsigned int *nlabelsp)
246 {
247 	unsigned int l1, l2, l, count1, count2, count, nlabels;
248 	int cdiff, ldiff, chdiff;
249 	unsigned char *label1, *label2;
250 	unsigned char *offsets1, *offsets2;
251 	dns_offsets_t odata1, odata2;
252 	dns_namereln_t namereln = dns_namereln_none;
253 
254 	/*
255 	 * Determine the relative ordering under the DNSSEC order relation of
256 	 * 'name1' and 'name2', and also determine the hierarchical
257 	 * relationship of the names.
258 	 *
259 	 * Note: It makes no sense for one of the names to be relative and the
260 	 * other absolute.  If both names are relative, then to be meaningfully
261 	 * compared the caller must ensure that they are both relative to the
262 	 * same domain.
263 	 */
264 
265 	REQUIRE(orderp != NULL);
266 	REQUIRE(nlabelsp != NULL);
267 	/*
268 	 * Either name1 is absolute and name2 is absolute, or neither is.
269 	 */
270 	REQUIRE((name1->attributes & DNS_NAMEATTR_ABSOLUTE) ==
271 		(name2->attributes & DNS_NAMEATTR_ABSOLUTE));
272 
273 	if (name1 == name2) {
274 		*orderp = 0;
275 		*nlabelsp = name1->labels;
276 		return (dns_namereln_equal);
277 	}
278 
279 	SETUP_OFFSETS(name1, offsets1, odata1);
280 	SETUP_OFFSETS(name2, offsets2, odata2);
281 
282 	nlabels = 0;
283 	l1 = name1->labels;
284 	l2 = name2->labels;
285 	if (l2 > l1) {
286 		l = l1;
287 		ldiff = 0 - (l2 - l1);
288 	} else {
289 		l = l2;
290 		ldiff = l1 - l2;
291 	}
292 
293 	offsets1 += l1;
294 	offsets2 += l2;
295 
296 	while (l > 0) {
297 		l--;
298 		offsets1--;
299 		offsets2--;
300 		label1 = &name1->ndata[*offsets1];
301 		label2 = &name2->ndata[*offsets2];
302 		count1 = *label1++;
303 		count2 = *label2++;
304 
305 		/*
306 		 * We dropped bitstring labels, and we don't support any
307 		 * other extended label types.
308 		 */
309 		INSIST(count1 <= 63 && count2 <= 63);
310 
311 		cdiff = (int)count1 - (int)count2;
312 		if (cdiff < 0)
313 			count = count1;
314 		else
315 			count = count2;
316 
317 		/* Loop unrolled for performance */
318 		while (count > 3) {
319 			chdiff = (int)maptolower[label1[0]] -
320 				 (int)maptolower[label2[0]];
321 			if (chdiff != 0) {
322 				*orderp = chdiff;
323 				goto done;
324 			}
325 			chdiff = (int)maptolower[label1[1]] -
326 				 (int)maptolower[label2[1]];
327 			if (chdiff != 0) {
328 				*orderp = chdiff;
329 				goto done;
330 			}
331 			chdiff = (int)maptolower[label1[2]] -
332 				 (int)maptolower[label2[2]];
333 			if (chdiff != 0) {
334 				*orderp = chdiff;
335 				goto done;
336 			}
337 			chdiff = (int)maptolower[label1[3]] -
338 				 (int)maptolower[label2[3]];
339 			if (chdiff != 0) {
340 				*orderp = chdiff;
341 				goto done;
342 			}
343 			count -= 4;
344 			label1 += 4;
345 			label2 += 4;
346 		}
347 		while (count-- > 0) {
348 			chdiff = (int)maptolower[*label1++] -
349 				 (int)maptolower[*label2++];
350 			if (chdiff != 0) {
351 				*orderp = chdiff;
352 				goto done;
353 			}
354 		}
355 		if (cdiff != 0) {
356 			*orderp = cdiff;
357 			goto done;
358 		}
359 		nlabels++;
360 	}
361 
362 	*orderp = ldiff;
363 	if (ldiff < 0)
364 		namereln = dns_namereln_contains;
365 	else if (ldiff > 0)
366 		namereln = dns_namereln_subdomain;
367 	else
368 		namereln = dns_namereln_equal;
369 	*nlabelsp = nlabels;
370 	return (namereln);
371 
372  done:
373 	*nlabelsp = nlabels;
374 	if (nlabels > 0)
375 		namereln = dns_namereln_commonancestor;
376 
377 	return (namereln);
378 }
379 
380 int
381 dns_name_compare(const dns_name_t *name1, const dns_name_t *name2) {
382 	int order;
383 	unsigned int nlabels;
384 
385 	/*
386 	 * Determine the relative ordering under the DNSSEC order relation of
387 	 * 'name1' and 'name2'.
388 	 *
389 	 * Note: It makes no sense for one of the names to be relative and the
390 	 * other absolute.  If both names are relative, then to be meaningfully
391 	 * compared the caller must ensure that they are both relative to the
392 	 * same domain.
393 	 */
394 
395 	(void)dns_name_fullcompare(name1, name2, &order, &nlabels);
396 
397 	return (order);
398 }
399 
400 int
401 dns_name_equal(const dns_name_t *name1, const dns_name_t *name2) {
402 	unsigned int l, count;
403 	unsigned char c;
404 	unsigned char *label1, *label2;
405 
406 	/*
407 	 * Are 'name1' and 'name2' equal?
408 	 *
409 	 * Note: It makes no sense for one of the names to be relative and the
410 	 * other absolute.  If both names are relative, then to be meaningfully
411 	 * compared the caller must ensure that they are both relative to the
412 	 * same domain.
413 	 */
414 
415 	/*
416 	 * Either name1 is absolute and name2 is absolute, or neither is.
417 	 */
418 	REQUIRE((name1->attributes & DNS_NAMEATTR_ABSOLUTE) ==
419 		(name2->attributes & DNS_NAMEATTR_ABSOLUTE));
420 
421 	if (name1 == name2)
422 		return (1);
423 
424 	if (name1->length != name2->length)
425 		return (0);
426 
427 	l = name1->labels;
428 
429 	if (l != name2->labels)
430 		return (0);
431 
432 	label1 = name1->ndata;
433 	label2 = name2->ndata;
434 	while (l-- > 0) {
435 		count = *label1++;
436 		if (count != *label2++)
437 			return (0);
438 
439 		INSIST(count <= 63); /* no bitstring support */
440 
441 		/* Loop unrolled for performance */
442 		while (count > 3) {
443 			c = maptolower[label1[0]];
444 			if (c != maptolower[label2[0]])
445 				return (0);
446 			c = maptolower[label1[1]];
447 			if (c != maptolower[label2[1]])
448 				return (0);
449 			c = maptolower[label1[2]];
450 			if (c != maptolower[label2[2]])
451 				return (0);
452 			c = maptolower[label1[3]];
453 			if (c != maptolower[label2[3]])
454 				return (0);
455 			count -= 4;
456 			label1 += 4;
457 			label2 += 4;
458 		}
459 		while (count-- > 0) {
460 			c = maptolower[*label1++];
461 			if (c != maptolower[*label2++])
462 				return (0);
463 		}
464 	}
465 
466 	return (1);
467 }
468 
469 int
470 dns_name_caseequal(const dns_name_t *name1, const dns_name_t *name2) {
471 
472 	/*
473 	 * Are 'name1' and 'name2' equal?
474 	 *
475 	 * Note: It makes no sense for one of the names to be relative and the
476 	 * other absolute.  If both names are relative, then to be meaningfully
477 	 * compared the caller must ensure that they are both relative to the
478 	 * same domain.
479 	 */
480 
481 	/*
482 	 * Either name1 is absolute and name2 is absolute, or neither is.
483 	 */
484 	REQUIRE((name1->attributes & DNS_NAMEATTR_ABSOLUTE) ==
485 		(name2->attributes & DNS_NAMEATTR_ABSOLUTE));
486 
487 	if (name1->length != name2->length)
488 		return (0);
489 
490 	if (memcmp(name1->ndata, name2->ndata, name1->length) != 0)
491 		return (0);
492 
493 	return (1);
494 }
495 
496 int
497 dns_name_issubdomain(const dns_name_t *name1, const dns_name_t *name2) {
498 	int order;
499 	unsigned int nlabels;
500 	dns_namereln_t namereln;
501 
502 	/*
503 	 * Is 'name1' a subdomain of 'name2'?
504 	 *
505 	 * Note: It makes no sense for one of the names to be relative and the
506 	 * other absolute.  If both names are relative, then to be meaningfully
507 	 * compared the caller must ensure that they are both relative to the
508 	 * same domain.
509 	 */
510 
511 	namereln = dns_name_fullcompare(name1, name2, &order, &nlabels);
512 	if (namereln == dns_namereln_subdomain ||
513 	    namereln == dns_namereln_equal)
514 		return (1);
515 
516 	return (0);
517 }
518 
519 unsigned int
520 dns_name_countlabels(const dns_name_t *name) {
521 	/*
522 	 * How many labels does 'name' have?
523 	 */
524 
525 	ENSURE(name->labels <= 128);
526 
527 	return (name->labels);
528 }
529 
530 void
531 dns_name_getlabel(const dns_name_t *name, unsigned int n, dns_label_t *label) {
532 	unsigned char *offsets;
533 	dns_offsets_t odata;
534 
535 	/*
536 	 * Make 'label' refer to the 'n'th least significant label of 'name'.
537 	 */
538 
539 	REQUIRE(name->labels > 0);
540 	REQUIRE(n < name->labels);
541 	REQUIRE(label != NULL);
542 
543 	SETUP_OFFSETS(name, offsets, odata);
544 
545 	label->base = &name->ndata[offsets[n]];
546 	if (n == name->labels - 1)
547 		label->length = name->length - offsets[n];
548 	else
549 		label->length = offsets[n + 1] - offsets[n];
550 }
551 
552 void
553 dns_name_getlabelsequence(const dns_name_t *source,
554 			  unsigned int first, unsigned int n,
555 			  dns_name_t *target)
556 {
557 	unsigned char *offsets;
558 	dns_offsets_t odata;
559 	unsigned int firstoffset, endoffset;
560 
561 	/*
562 	 * Make 'target' refer to the 'n' labels including and following
563 	 * 'first' in 'source'.
564 	 */
565 
566 	REQUIRE(first <= source->labels);
567 	REQUIRE(n <= source->labels - first); /* note first+n could overflow */
568 	REQUIRE(BINDABLE(target));
569 
570 	SETUP_OFFSETS(source, offsets, odata);
571 
572 	if (first == source->labels)
573 		firstoffset = source->length;
574 	else
575 		firstoffset = offsets[first];
576 
577 	if (first + n == source->labels)
578 		endoffset = source->length;
579 	else
580 		endoffset = offsets[first + n];
581 
582 	target->ndata = &source->ndata[firstoffset];
583 	target->length = endoffset - firstoffset;
584 
585 	if (first + n == source->labels && n > 0 &&
586 	    (source->attributes & DNS_NAMEATTR_ABSOLUTE) != 0)
587 		target->attributes |= DNS_NAMEATTR_ABSOLUTE;
588 	else
589 		target->attributes &= ~DNS_NAMEATTR_ABSOLUTE;
590 
591 	target->labels = n;
592 
593 	/*
594 	 * If source and target are the same, and we're making target
595 	 * a prefix of source, the offsets table is correct already
596 	 * so we don't need to call set_offsets().
597 	 */
598 	if (target->offsets != NULL &&
599 	    (target != source || first != 0))
600 		set_offsets(target, target->offsets, NULL);
601 }
602 
603 void
604 dns_name_clone(const dns_name_t *source, dns_name_t *target) {
605 
606 	/*
607 	 * Make 'target' refer to the same name as 'source'.
608 	 */
609 
610 	REQUIRE(BINDABLE(target));
611 
612 	target->ndata = source->ndata;
613 	target->length = source->length;
614 	target->labels = source->labels;
615 	target->attributes = source->attributes &
616 		(unsigned int)~(DNS_NAMEATTR_READONLY | DNS_NAMEATTR_DYNAMIC |
617 				DNS_NAMEATTR_DYNOFFSETS);
618 	if (target->offsets != NULL && source->labels > 0) {
619 		if (source->offsets != NULL)
620 			memmove(target->offsets, source->offsets,
621 				source->labels);
622 		else
623 			set_offsets(target, target->offsets, NULL);
624 	}
625 }
626 
627 void
628 dns_name_fromregion(dns_name_t *name, const isc_region_t *r) {
629 	unsigned char *offsets;
630 	dns_offsets_t odata;
631 	unsigned int len;
632 	isc_region_t r2;
633 
634 	/*
635 	 * Make 'name' refer to region 'r'.
636 	 */
637 
638 	REQUIRE(r != NULL);
639 	REQUIRE(BINDABLE(name));
640 
641 	INIT_OFFSETS(name, offsets, odata);
642 
643 	if (name->buffer != NULL) {
644 		isc_buffer_clear(name->buffer);
645 		isc_buffer_availableregion(name->buffer, &r2);
646 		len = (r->length < r2.length) ? r->length : r2.length;
647 		if (len > DNS_NAME_MAXWIRE)
648 			len = DNS_NAME_MAXWIRE;
649 		if (len != 0)
650 			memmove(r2.base, r->base, len);
651 		name->ndata = r2.base;
652 		name->length = len;
653 	} else {
654 		name->ndata = r->base;
655 		name->length = (r->length <= DNS_NAME_MAXWIRE) ?
656 			r->length : DNS_NAME_MAXWIRE;
657 	}
658 
659 	if (r->length > 0)
660 		set_offsets(name, offsets, name);
661 	else {
662 		name->labels = 0;
663 		name->attributes &= ~DNS_NAMEATTR_ABSOLUTE;
664 	}
665 
666 	if (name->buffer != NULL)
667 		isc_buffer_add(name->buffer, name->length);
668 }
669 
670 void
671 dns_name_toregion(dns_name_t *name, isc_region_t *r) {
672 	/*
673 	 * Make 'r' refer to 'name'.
674 	 */
675 
676 	REQUIRE(r != NULL);
677 
678 	r->base = name->ndata;
679 	r->length = name->length;
680 }
681 
682 isc_result_t
683 dns_name_fromtext(dns_name_t *name, isc_buffer_t *source,
684 		  const dns_name_t *origin, unsigned int options,
685 		  isc_buffer_t *target)
686 {
687 	unsigned char *ndata, *label = NULL;
688 	char *tdata;
689 	char c;
690 	ft_state state;
691 	unsigned int value = 0, count = 0;
692 	unsigned int n1 = 0, n2 = 0;
693 	unsigned int tlen, nrem, nused, digits = 0, labels, tused;
694 	int done;
695 	unsigned char *offsets;
696 	dns_offsets_t odata;
697 	int downcase;
698 
699 	/*
700 	 * Convert the textual representation of a DNS name at source
701 	 * into uncompressed wire form stored in target.
702 	 *
703 	 * Notes:
704 	 *	Relative domain names will have 'origin' appended to them
705 	 *	unless 'origin' is NULL, in which case relative domain names
706 	 *	will remain relative.
707 	 */
708 
709 	downcase = (options & DNS_NAME_DOWNCASE) != 0;
710 
711 	if (target == NULL && name->buffer != NULL) {
712 		target = name->buffer;
713 		isc_buffer_clear(target);
714 	}
715 
716 	REQUIRE(BINDABLE(name));
717 
718 	INIT_OFFSETS(name, offsets, odata);
719 	offsets[0] = 0;
720 
721 	/*
722 	 * Make 'name' empty in case of failure.
723 	 */
724 	MAKE_EMPTY(name);
725 
726 	/*
727 	 * Set up the state machine.
728 	 */
729 	tdata = (char *)source->base + source->current;
730 	tlen = isc_buffer_remaininglength(source);
731 	tused = 0;
732 	ndata = isc_buffer_used(target);
733 	nrem = isc_buffer_availablelength(target);
734 	if (nrem > 255)
735 		nrem = 255;
736 	nused = 0;
737 	labels = 0;
738 	done = 0;
739 	state = ft_init;
740 
741 	while (nrem > 0 && tlen > 0 && !done) {
742 		c = *tdata++;
743 		tlen--;
744 		tused++;
745 
746 		switch (state) {
747 		case ft_init:
748 			/*
749 			 * Is this the root name?
750 			 */
751 			if (c == '.') {
752 				if (tlen != 0)
753 					return (DNS_R_EMPTYLABEL);
754 				labels++;
755 				*ndata++ = 0;
756 				nrem--;
757 				nused++;
758 				done = 1;
759 				break;
760 			}
761 			if (c == '@' && tlen == 0) {
762 				state = ft_at;
763 				break;
764 			}
765 
766 			/* FALLTHROUGH */
767 		case ft_start:
768 			label = ndata;
769 			ndata++;
770 			nrem--;
771 			nused++;
772 			count = 0;
773 			if (c == '\\') {
774 				state = ft_initialescape;
775 				break;
776 			}
777 			state = ft_ordinary;
778 			if (nrem == 0)
779 				return (ISC_R_NOSPACE);
780 			/* FALLTHROUGH */
781 		case ft_ordinary:
782 			if (c == '.') {
783 				if (count == 0)
784 					return (DNS_R_EMPTYLABEL);
785 				*label = count;
786 				labels++;
787 				INSIST(labels <= 127);
788 				offsets[labels] = nused;
789 				if (tlen == 0) {
790 					labels++;
791 					*ndata++ = 0;
792 					nrem--;
793 					nused++;
794 					done = 1;
795 				}
796 				state = ft_start;
797 			} else if (c == '\\') {
798 				state = ft_escape;
799 			} else {
800 				if (count >= 63)
801 					return (DNS_R_LABELTOOLONG);
802 				count++;
803 				CONVERTTOASCII(c);
804 				if (downcase)
805 					c = maptolower[c & 0xff];
806 				*ndata++ = c;
807 				nrem--;
808 				nused++;
809 			}
810 			break;
811 		case ft_initialescape:
812 			if (c == '[') {
813 				/*
814 				 * This looks like a bitstring label, which
815 				 * was deprecated.  Intentionally drop it.
816 				 */
817 				return (DNS_R_BADLABELTYPE);
818 			}
819 			state = ft_escape;
820 			POST(state);
821 			/* FALLTHROUGH */
822 		case ft_escape:
823 			if (!isdigit(c & 0xff)) {
824 				if (count >= 63)
825 					return (DNS_R_LABELTOOLONG);
826 				count++;
827 				CONVERTTOASCII(c);
828 				if (downcase)
829 					c = maptolower[c & 0xff];
830 				*ndata++ = c;
831 				nrem--;
832 				nused++;
833 				state = ft_ordinary;
834 				break;
835 			}
836 			digits = 0;
837 			value = 0;
838 			state = ft_escdecimal;
839 			/* FALLTHROUGH */
840 		case ft_escdecimal:
841 			if (!isdigit(c & 0xff))
842 				return (DNS_R_BADESCAPE);
843 			value *= 10;
844 			value += digitvalue[c & 0xff];
845 			digits++;
846 			if (digits == 3) {
847 				if (value > 255)
848 					return (DNS_R_BADESCAPE);
849 				if (count >= 63)
850 					return (DNS_R_LABELTOOLONG);
851 				count++;
852 				if (downcase)
853 					value = maptolower[value];
854 				*ndata++ = value;
855 				nrem--;
856 				nused++;
857 				state = ft_ordinary;
858 			}
859 			break;
860 		default:
861 			FATAL_ERROR(__FILE__, __LINE__,
862 				    "Unexpected state %d", state);
863 			/* Does not return. */
864 		}
865 	}
866 
867 	if (!done) {
868 		if (nrem == 0)
869 			return (ISC_R_NOSPACE);
870 		INSIST(tlen == 0);
871 		if (state != ft_ordinary && state != ft_at)
872 			return (ISC_R_UNEXPECTEDEND);
873 		if (state == ft_ordinary) {
874 			INSIST(count != 0);
875 			*label = count;
876 			labels++;
877 			INSIST(labels <= 127);
878 			offsets[labels] = nused;
879 		}
880 		if (origin != NULL) {
881 			if (nrem < origin->length)
882 				return (ISC_R_NOSPACE);
883 			label = origin->ndata;
884 			n1 = origin->length;
885 			nrem -= n1;
886 			POST(nrem);
887 			while (n1 > 0) {
888 				n2 = *label++;
889 				INSIST(n2 <= 63); /* no bitstring support */
890 				*ndata++ = n2;
891 				n1 -= n2 + 1;
892 				nused += n2 + 1;
893 				while (n2 > 0) {
894 					c = *label++;
895 					if (downcase)
896 						c = maptolower[c & 0xff];
897 					*ndata++ = c;
898 					n2--;
899 				}
900 				labels++;
901 				if (n1 > 0) {
902 					INSIST(labels <= 127);
903 					offsets[labels] = nused;
904 				}
905 			}
906 			if ((origin->attributes & DNS_NAMEATTR_ABSOLUTE) != 0)
907 				name->attributes |= DNS_NAMEATTR_ABSOLUTE;
908 		}
909 	} else
910 		name->attributes |= DNS_NAMEATTR_ABSOLUTE;
911 
912 	name->ndata = (unsigned char *)target->base + target->used;
913 	name->labels = labels;
914 	name->length = nused;
915 
916 	isc_buffer_forward(source, tused);
917 	isc_buffer_add(target, name->length);
918 
919 	return (ISC_R_SUCCESS);
920 }
921 
922 isc_result_t
923 dns_name_totext(dns_name_t *name, int omit_final_dot,
924 		isc_buffer_t *target)
925 {
926 	unsigned int options = DNS_NAME_MASTERFILE;
927 
928 	if (omit_final_dot)
929 		options |= DNS_NAME_OMITFINALDOT;
930 	return (dns_name_totext2(name, options, target));
931 }
932 
933 isc_result_t
934 dns_name_totext2(dns_name_t *name, unsigned int options, isc_buffer_t *target)
935 {
936 	unsigned char *ndata;
937 	char *tdata;
938 	unsigned int nlen, tlen;
939 	unsigned char c;
940 	unsigned int trem, count;
941 	unsigned int labels;
942 	int saw_root = 0;
943 	int omit_final_dot = options & DNS_NAME_OMITFINALDOT;
944 
945 	/*
946 	 * This function assumes the name is in proper uncompressed
947 	 * wire format.
948 	 */
949 
950 	ndata = name->ndata;
951 	nlen = name->length;
952 	labels = name->labels;
953 	tdata = isc_buffer_used(target);
954 	tlen = isc_buffer_availablelength(target);
955 
956 	trem = tlen;
957 
958 	if (labels == 0 && nlen == 0) {
959 		/*
960 		 * Special handling for an empty name.
961 		 */
962 		if (trem == 0)
963 			return (ISC_R_NOSPACE);
964 
965 		/*
966 		 * The names of these booleans are misleading in this case.
967 		 * This empty name is not necessarily from the root node of
968 		 * the DNS root zone, nor is a final dot going to be included.
969 		 * They need to be set this way, though, to keep the "@"
970 		 * from being trounced.
971 		 */
972 		saw_root = 1;
973 		omit_final_dot = 0;
974 		*tdata++ = '@';
975 		trem--;
976 
977 		/*
978 		 * Skip the while() loop.
979 		 */
980 		nlen = 0;
981 	} else if (nlen == 1 && labels == 1 && *ndata == '\0') {
982 		/*
983 		 * Special handling for the root label.
984 		 */
985 		if (trem == 0)
986 			return (ISC_R_NOSPACE);
987 
988 		saw_root = 1;
989 		omit_final_dot = 0;
990 		*tdata++ = '.';
991 		trem--;
992 
993 		/*
994 		 * Skip the while() loop.
995 		 */
996 		nlen = 0;
997 	}
998 
999 	while (labels > 0 && nlen > 0 && trem > 0) {
1000 		labels--;
1001 		count = *ndata++;
1002 		nlen--;
1003 		if (count == 0) {
1004 			saw_root = 1;
1005 			break;
1006 		}
1007 		if (count < 64) {
1008 			INSIST(nlen >= count);
1009 			while (count > 0) {
1010 				c = *ndata;
1011 				switch (c) {
1012 				/* Special modifiers in zone files. */
1013 				case 0x40: /* '@' */
1014 				case 0x24: /* '$' */
1015 					if ((options & DNS_NAME_MASTERFILE) == 0)
1016 						goto no_escape;
1017 					/* FALLTHROUGH */
1018 				case 0x22: /* '"' */
1019 				case 0x28: /* '(' */
1020 				case 0x29: /* ')' */
1021 				case 0x2E: /* '.' */
1022 				case 0x3B: /* ';' */
1023 				case 0x5C: /* '\\' */
1024 					if (trem < 2)
1025 						return (ISC_R_NOSPACE);
1026 					*tdata++ = '\\';
1027 					CONVERTFROMASCII(c);
1028 					*tdata++ = c;
1029 					ndata++;
1030 					trem -= 2;
1031 					nlen--;
1032 					break;
1033 				no_escape:
1034 				default:
1035 					if (c > 0x20 && c < 0x7f) {
1036 						if (trem == 0)
1037 							return (ISC_R_NOSPACE);
1038 						CONVERTFROMASCII(c);
1039 						*tdata++ = c;
1040 						ndata++;
1041 						trem--;
1042 						nlen--;
1043 					} else {
1044 						if (trem < 4)
1045 							return (ISC_R_NOSPACE);
1046 						*tdata++ = 0x5c;
1047 						*tdata++ = 0x30 +
1048 							   ((c / 100) % 10);
1049 						*tdata++ = 0x30 +
1050 							   ((c / 10) % 10);
1051 						*tdata++ = 0x30 + (c % 10);
1052 						trem -= 4;
1053 						ndata++;
1054 						nlen--;
1055 					}
1056 				}
1057 				count--;
1058 			}
1059 		} else {
1060 			FATAL_ERROR(__FILE__, __LINE__,
1061 				    "Unexpected label type %02x", count);
1062 			/* NOTREACHED */
1063 		}
1064 
1065 		/*
1066 		 * The following assumes names are absolute.  If not, we
1067 		 * fix things up later.  Note that this means that in some
1068 		 * cases one more byte of text buffer is required than is
1069 		 * needed in the final output.
1070 		 */
1071 		if (trem == 0)
1072 			return (ISC_R_NOSPACE);
1073 		*tdata++ = '.';
1074 		trem--;
1075 	}
1076 
1077 	if (nlen != 0 && trem == 0)
1078 		return (ISC_R_NOSPACE);
1079 
1080 	if (!saw_root || omit_final_dot)
1081 		trem++;
1082 
1083 	isc_buffer_add(target, tlen - trem);
1084 
1085 	return (ISC_R_SUCCESS);
1086 }
1087 
1088 isc_result_t
1089 dns_name_downcase(dns_name_t *source, dns_name_t *name, isc_buffer_t *target) {
1090 	unsigned char *sndata, *ndata;
1091 	unsigned int nlen, count, labels;
1092 	isc_buffer_t buffer;
1093 
1094 	/*
1095 	 * Downcase 'source'.
1096 	 */
1097 
1098 	if (source == name) {
1099 		REQUIRE((name->attributes & DNS_NAMEATTR_READONLY) == 0);
1100 		isc_buffer_init(&buffer, source->ndata, source->length);
1101 		target = &buffer;
1102 		ndata = source->ndata;
1103 	} else {
1104 		REQUIRE(BINDABLE(name));
1105 		if (target == NULL) {
1106 			target = name->buffer;
1107 			isc_buffer_clear(name->buffer);
1108 		}
1109 		ndata = (unsigned char *)target->base + target->used;
1110 		name->ndata = ndata;
1111 	}
1112 
1113 	sndata = source->ndata;
1114 	nlen = source->length;
1115 	labels = source->labels;
1116 
1117 	if (nlen > (target->length - target->used)) {
1118 		MAKE_EMPTY(name);
1119 		return (ISC_R_NOSPACE);
1120 	}
1121 
1122 	while (labels > 0 && nlen > 0) {
1123 		labels--;
1124 		count = *sndata++;
1125 		*ndata++ = count;
1126 		nlen--;
1127 		if (count < 64) {
1128 			INSIST(nlen >= count);
1129 			while (count > 0) {
1130 				*ndata++ = maptolower[(*sndata++)];
1131 				nlen--;
1132 				count--;
1133 			}
1134 		} else {
1135 			FATAL_ERROR(__FILE__, __LINE__,
1136 				    "Unexpected label type %02x", count);
1137 			/* Does not return. */
1138 		}
1139 	}
1140 
1141 	if (source != name) {
1142 		name->labels = source->labels;
1143 		name->length = source->length;
1144 		if ((source->attributes & DNS_NAMEATTR_ABSOLUTE) != 0)
1145 			name->attributes = DNS_NAMEATTR_ABSOLUTE;
1146 		else
1147 			name->attributes = 0;
1148 		if (name->labels > 0 && name->offsets != NULL)
1149 			set_offsets(name, name->offsets, NULL);
1150 	}
1151 
1152 	isc_buffer_add(target, name->length);
1153 
1154 	return (ISC_R_SUCCESS);
1155 }
1156 
1157 static void
1158 set_offsets(const dns_name_t *name, unsigned char *offsets,
1159 	    dns_name_t *set_name)
1160 {
1161 	unsigned int offset, count, length, nlabels;
1162 	unsigned char *ndata;
1163 	int absolute;
1164 
1165 	ndata = name->ndata;
1166 	length = name->length;
1167 	offset = 0;
1168 	nlabels = 0;
1169 	absolute = 0;
1170 	while (offset != length) {
1171 		INSIST(nlabels < 128);
1172 		offsets[nlabels++] = offset;
1173 		count = *ndata++;
1174 		offset++;
1175 		INSIST(count <= 63);
1176 		offset += count;
1177 		ndata += count;
1178 		INSIST(offset <= length);
1179 		if (count == 0) {
1180 			absolute = 1;
1181 			break;
1182 		}
1183 	}
1184 	if (set_name != NULL) {
1185 		INSIST(set_name == name);
1186 
1187 		set_name->labels = nlabels;
1188 		set_name->length = offset;
1189 		if (absolute)
1190 			set_name->attributes |= DNS_NAMEATTR_ABSOLUTE;
1191 		else
1192 			set_name->attributes &= ~DNS_NAMEATTR_ABSOLUTE;
1193 	}
1194 	INSIST(nlabels == name->labels);
1195 	INSIST(offset == name->length);
1196 }
1197 
1198 isc_result_t
1199 dns_name_fromwire(dns_name_t *name, isc_buffer_t *source,
1200 		  dns_decompress_t *dctx, unsigned int options,
1201 		  isc_buffer_t *target)
1202 {
1203 	unsigned char *cdata, *ndata;
1204 	unsigned int cused; /* Bytes of compressed name data used */
1205 	unsigned int nused, labels, n, nmax;
1206 	unsigned int current, new_current, biggest_pointer;
1207 	int done;
1208 	fw_state state = fw_start;
1209 	unsigned int c;
1210 	unsigned char *offsets;
1211 	dns_offsets_t odata;
1212 	int downcase;
1213 	int seen_pointer;
1214 
1215 	/*
1216 	 * Copy the possibly-compressed name at source into target,
1217 	 * decompressing it.  Loop prevention is performed by checking
1218 	 * the new pointer against biggest_pointer.
1219 	 */
1220 
1221 	downcase = (options & DNS_NAME_DOWNCASE) != 0;
1222 
1223 	if (target == NULL && name->buffer != NULL) {
1224 		target = name->buffer;
1225 		isc_buffer_clear(target);
1226 	}
1227 
1228 	REQUIRE(dctx != NULL);
1229 	REQUIRE(BINDABLE(name));
1230 
1231 	INIT_OFFSETS(name, offsets, odata);
1232 
1233 	/*
1234 	 * Make 'name' empty in case of failure.
1235 	 */
1236 	MAKE_EMPTY(name);
1237 
1238 	/*
1239 	 * Initialize things to make the compiler happy; they're not required.
1240 	 */
1241 	n = 0;
1242 	new_current = 0;
1243 
1244 	/*
1245 	 * Set up.
1246 	 */
1247 	labels = 0;
1248 	done = 0;
1249 
1250 	ndata = isc_buffer_used(target);
1251 	nused = 0;
1252 	seen_pointer = 0;
1253 
1254 	/*
1255 	 * Find the maximum number of uncompressed target name
1256 	 * bytes we are willing to generate.  This is the smaller
1257 	 * of the available target buffer length and the
1258 	 * maximum legal domain name length (255).
1259 	 */
1260 	nmax = isc_buffer_availablelength(target);
1261 	if (nmax > DNS_NAME_MAXWIRE)
1262 		nmax = DNS_NAME_MAXWIRE;
1263 
1264 	cdata = isc_buffer_current(source);
1265 	cused = 0;
1266 
1267 	current = source->current;
1268 	biggest_pointer = current;
1269 
1270 	/*
1271 	 * Note:  The following code is not optimized for speed, but
1272 	 * rather for correctness.  Speed will be addressed in the future.
1273 	 */
1274 
1275 	while (current < source->active && !done) {
1276 		c = *cdata++;
1277 		current++;
1278 		if (!seen_pointer)
1279 			cused++;
1280 
1281 		switch (state) {
1282 		case fw_start:
1283 			if (c < 64) {
1284 				offsets[labels] = nused;
1285 				labels++;
1286 				if (nused + c + 1 > nmax)
1287 					goto full;
1288 				nused += c + 1;
1289 				*ndata++ = c;
1290 				if (c == 0)
1291 					done = 1;
1292 				n = c;
1293 				state = fw_ordinary;
1294 			} else if (c >= 128 && c < 192) {
1295 				/*
1296 				 * 14 bit local compression pointer.
1297 				 * Local compression is no longer an
1298 				 * IETF draft.
1299 				 */
1300 				return (DNS_R_BADLABELTYPE);
1301 			} else if (c >= 192) {
1302 				/*
1303 				 * Ordinary 14-bit pointer.
1304 				 */
1305 				if ((dctx->allowed & DNS_COMPRESS_GLOBAL14) ==
1306 				    0)
1307 					return (DNS_R_DISALLOWED);
1308 				new_current = c & 0x3F;
1309 				state = fw_newcurrent;
1310 			} else
1311 				return (DNS_R_BADLABELTYPE);
1312 			break;
1313 		case fw_ordinary:
1314 			if (downcase)
1315 				c = maptolower[c];
1316 			*ndata++ = c;
1317 			n--;
1318 			if (n == 0)
1319 				state = fw_start;
1320 			break;
1321 		case fw_newcurrent:
1322 			new_current *= 256;
1323 			new_current += c;
1324 			if (new_current >= biggest_pointer)
1325 				return (DNS_R_BADPOINTER);
1326 			biggest_pointer = new_current;
1327 			current = new_current;
1328 			cdata = (unsigned char *)source->base + current;
1329 			seen_pointer = 1;
1330 			state = fw_start;
1331 			break;
1332 		default:
1333 			FATAL_ERROR(__FILE__, __LINE__,
1334 				    "Unknown state %d", state);
1335 			/* Does not return. */
1336 		}
1337 	}
1338 
1339 	if (!done)
1340 		return (ISC_R_UNEXPECTEDEND);
1341 
1342 	name->ndata = (unsigned char *)target->base + target->used;
1343 	name->labels = labels;
1344 	name->length = nused;
1345 	name->attributes |= DNS_NAMEATTR_ABSOLUTE;
1346 
1347 	isc_buffer_forward(source, cused);
1348 	isc_buffer_add(target, name->length);
1349 
1350 	return (ISC_R_SUCCESS);
1351 
1352  full:
1353 	if (nmax == DNS_NAME_MAXWIRE)
1354 		/*
1355 		 * The name did not fit even though we had a buffer
1356 		 * big enough to fit a maximum-length name.
1357 		 */
1358 		return (DNS_R_NAMETOOLONG);
1359 	else
1360 		/*
1361 		 * The name might fit if only the caller could give us a
1362 		 * big enough buffer.
1363 		 */
1364 		return (ISC_R_NOSPACE);
1365 }
1366 
1367 isc_result_t
1368 dns_name_towire(const dns_name_t *name, dns_compress_t *cctx,
1369 		isc_buffer_t *target)
1370 {
1371 	unsigned int methods;
1372 	uint16_t offset;
1373 	dns_name_t gp;	/* Global compression prefix */
1374 	int gf;	/* Global compression target found */
1375 	uint16_t go;	/* Global compression offset */
1376 	dns_offsets_t clo;
1377 	dns_name_t clname;
1378 
1379 	/*
1380 	 * Convert 'name' into wire format, compressing it as specified by the
1381 	 * compression context 'cctx', and storing the result in 'target'.
1382 	 */
1383 
1384 	REQUIRE(cctx != NULL);
1385 
1386 	/*
1387 	 * If 'name' doesn't have an offsets table, make a clone which
1388 	 * has one.
1389 	 */
1390 	if (name->offsets == NULL) {
1391 		dns_name_init(&clname, clo);
1392 		dns_name_clone(name, &clname);
1393 		name = &clname;
1394 	}
1395 	dns_name_init(&gp, NULL);
1396 
1397 	offset = target->used;	/*XXX*/
1398 
1399 	methods = dns_compress_getmethods(cctx);
1400 
1401 	if ((name->attributes & DNS_NAMEATTR_NOCOMPRESS) == 0 &&
1402 	    (methods & DNS_COMPRESS_GLOBAL14) != 0)
1403 		gf = dns_compress_findglobal(cctx, name, &gp, &go);
1404 	else
1405 		gf = 0;
1406 
1407 	/*
1408 	 * If the offset is too high for 14 bit global compression, we're
1409 	 * out of luck.
1410 	 */
1411 	if (gf && go >= 0x4000)
1412 		gf = 0;
1413 
1414 	/*
1415 	 * Will the compression pointer reduce the message size?
1416 	 */
1417 	if (gf && (gp.length + 2) >= name->length)
1418 		gf = 0;
1419 
1420 	if (gf) {
1421 		if (target->length - target->used < gp.length)
1422 			return (ISC_R_NOSPACE);
1423 		if (gp.length != 0) {
1424 			unsigned char *base = target->base;
1425 			(void)memmove(base + target->used, gp.ndata,
1426 				      (size_t)gp.length);
1427 		}
1428 		isc_buffer_add(target, gp.length);
1429 		go |= 0xc000;
1430 		if (target->length - target->used < 2)
1431 			return (ISC_R_NOSPACE);
1432 		isc_buffer_putuint16(target, go);
1433 		if (gp.length != 0)
1434 			dns_compress_add(cctx, name, &gp, offset);
1435 	} else {
1436 		if (target->length - target->used < name->length)
1437 			return (ISC_R_NOSPACE);
1438 		if (name->length != 0) {
1439 			unsigned char *base = target->base;
1440 			(void)memmove(base + target->used, name->ndata,
1441 				      (size_t)name->length);
1442 		}
1443 		isc_buffer_add(target, name->length);
1444 		dns_compress_add(cctx, name, name, offset);
1445 	}
1446 	return (ISC_R_SUCCESS);
1447 }
1448 
1449 isc_result_t
1450 dns_name_concatenate(dns_name_t *prefix, dns_name_t *suffix, dns_name_t *name,
1451 		     isc_buffer_t *target)
1452 {
1453 	unsigned char *ndata, *offsets;
1454 	unsigned int nrem, labels, prefix_length, length;
1455 	int copy_prefix = 1;
1456 	int copy_suffix = 1;
1457 	int absolute = 0;
1458 	dns_name_t tmp_name;
1459 	dns_offsets_t odata;
1460 
1461 	/*
1462 	 * Concatenate 'prefix' and 'suffix'.
1463 	 */
1464 
1465 	if (prefix == NULL || prefix->labels == 0)
1466 		copy_prefix = 0;
1467 	if (suffix == NULL || suffix->labels == 0)
1468 		copy_suffix = 0;
1469 	if (copy_prefix &&
1470 	    (prefix->attributes & DNS_NAMEATTR_ABSOLUTE) != 0) {
1471 		absolute = 1;
1472 		REQUIRE(!copy_suffix);
1473 	}
1474 	if (name == NULL) {
1475 		dns_name_init(&tmp_name, odata);
1476 		name = &tmp_name;
1477 	}
1478 	if (target == NULL) {
1479 		INSIST(name->buffer != NULL);
1480 		target = name->buffer;
1481 		isc_buffer_clear(name->buffer);
1482 	}
1483 
1484 	REQUIRE(BINDABLE(name));
1485 
1486 	/*
1487 	 * Set up.
1488 	 */
1489 	nrem = target->length - target->used;
1490 	ndata = (unsigned char *)target->base + target->used;
1491 	if (nrem > DNS_NAME_MAXWIRE)
1492 		nrem = DNS_NAME_MAXWIRE;
1493 	length = 0;
1494 	prefix_length = 0;
1495 	labels = 0;
1496 	if (copy_prefix) {
1497 		prefix_length = prefix->length;
1498 		length += prefix_length;
1499 		labels += prefix->labels;
1500 	}
1501 	if (copy_suffix) {
1502 		length += suffix->length;
1503 		labels += suffix->labels;
1504 	}
1505 	if (length > DNS_NAME_MAXWIRE) {
1506 		MAKE_EMPTY(name);
1507 		return (DNS_R_NAMETOOLONG);
1508 	}
1509 	if (length > nrem) {
1510 		MAKE_EMPTY(name);
1511 		return (ISC_R_NOSPACE);
1512 	}
1513 
1514 	if (copy_suffix) {
1515 		if ((suffix->attributes & DNS_NAMEATTR_ABSOLUTE) != 0)
1516 			absolute = 1;
1517 		memmove(ndata + prefix_length, suffix->ndata, suffix->length);
1518 	}
1519 
1520 	/*
1521 	 * If 'prefix' and 'name' are the same object, and the object has
1522 	 * a dedicated buffer, and we're using it, then we don't have to
1523 	 * copy anything.
1524 	 */
1525 	if (copy_prefix && (prefix != name || prefix->buffer != target))
1526 		memmove(ndata, prefix->ndata, prefix_length);
1527 
1528 	name->ndata = ndata;
1529 	name->labels = labels;
1530 	name->length = length;
1531 	if (absolute)
1532 		name->attributes = DNS_NAMEATTR_ABSOLUTE;
1533 	else
1534 		name->attributes = 0;
1535 
1536 	if (name->labels > 0 && name->offsets != NULL) {
1537 		INIT_OFFSETS(name, offsets, odata);
1538 		set_offsets(name, offsets, NULL);
1539 	}
1540 
1541 	isc_buffer_add(target, name->length);
1542 
1543 	return (ISC_R_SUCCESS);
1544 }
1545 
1546 isc_result_t
1547 dns_name_dup(const dns_name_t *source,
1548 	     dns_name_t *target)
1549 {
1550 	/*
1551 	 * Make 'target' a dynamically allocated copy of 'source'.
1552 	 */
1553 
1554 	REQUIRE(source->length > 0);
1555 	REQUIRE(BINDABLE(target));
1556 
1557 	/*
1558 	 * Make 'target' empty in case of failure.
1559 	 */
1560 	MAKE_EMPTY(target);
1561 
1562 	target->ndata = malloc(source->length);
1563 	if (target->ndata == NULL)
1564 		return (ISC_R_NOMEMORY);
1565 
1566 	memmove(target->ndata, source->ndata, source->length);
1567 
1568 	target->length = source->length;
1569 	target->labels = source->labels;
1570 	target->attributes = DNS_NAMEATTR_DYNAMIC;
1571 	if ((source->attributes & DNS_NAMEATTR_ABSOLUTE) != 0)
1572 		target->attributes |= DNS_NAMEATTR_ABSOLUTE;
1573 	if (target->offsets != NULL) {
1574 		if (source->offsets != NULL)
1575 			memmove(target->offsets, source->offsets,
1576 				source->labels);
1577 		else
1578 			set_offsets(target, target->offsets, NULL);
1579 	}
1580 
1581 	return (ISC_R_SUCCESS);
1582 }
1583 
1584 isc_result_t
1585 dns_name_dupwithoffsets(dns_name_t *source,
1586 			dns_name_t *target)
1587 {
1588 	/*
1589 	 * Make 'target' a read-only dynamically allocated copy of 'source'.
1590 	 * 'target' will also have a dynamically allocated offsets table.
1591 	 */
1592 
1593 	REQUIRE(source->length > 0);
1594 	REQUIRE(BINDABLE(target));
1595 	REQUIRE(target->offsets == NULL);
1596 
1597 	/*
1598 	 * Make 'target' empty in case of failure.
1599 	 */
1600 	MAKE_EMPTY(target);
1601 
1602 	target->ndata = malloc(source->length + source->labels);
1603 	if (target->ndata == NULL)
1604 		return (ISC_R_NOMEMORY);
1605 
1606 	memmove(target->ndata, source->ndata, source->length);
1607 
1608 	target->length = source->length;
1609 	target->labels = source->labels;
1610 	target->attributes = DNS_NAMEATTR_DYNAMIC | DNS_NAMEATTR_DYNOFFSETS |
1611 		DNS_NAMEATTR_READONLY;
1612 	if ((source->attributes & DNS_NAMEATTR_ABSOLUTE) != 0)
1613 		target->attributes |= DNS_NAMEATTR_ABSOLUTE;
1614 	target->offsets = target->ndata + source->length;
1615 	if (source->offsets != NULL)
1616 		memmove(target->offsets, source->offsets, source->labels);
1617 	else
1618 		set_offsets(target, target->offsets, NULL);
1619 
1620 	return (ISC_R_SUCCESS);
1621 }
1622 
1623 void
1624 dns_name_free(dns_name_t *name) {
1625 	/*
1626 	 * Free 'name'.
1627 	 */
1628 
1629 	REQUIRE((name->attributes & DNS_NAMEATTR_DYNAMIC) != 0);
1630 
1631 	free(name->ndata);
1632 	dns_name_invalidate(name);
1633 }
1634 
1635 int
1636 dns_name_dynamic(dns_name_t *name) {
1637 
1638 	/*
1639 	 * Returns whether there is dynamic memory associated with this name.
1640 	 */
1641 
1642 	return ((name->attributes & DNS_NAMEATTR_DYNAMIC) != 0 ?
1643 		1 : 0);
1644 }
1645 
1646 void
1647 dns_name_format(dns_name_t *name, char *cp, unsigned int size) {
1648 	isc_result_t result;
1649 	isc_buffer_t buf;
1650 
1651 	REQUIRE(size > 0);
1652 
1653 	/*
1654 	 * Leave room for null termination after buffer.
1655 	 */
1656 	isc_buffer_init(&buf, cp, size - 1);
1657 	result = dns_name_totext(name, 1, &buf);
1658 	if (result == ISC_R_SUCCESS) {
1659 		/*
1660 		 * Null terminate.
1661 		 */
1662 		isc_region_t r;
1663 		isc_buffer_usedregion(&buf, &r);
1664 		((char *) r.base)[r.length] = '\0';
1665 
1666 	} else
1667 		snprintf(cp, size, "<unknown>");
1668 }
1669 
1670 /*
1671  * dns_name_fromstring() -- convert directly from a string to a name,
1672  * allocating memory as needed
1673  */
1674 isc_result_t
1675 dns_name_fromstring2(dns_name_t *target, const char *src,
1676 		     const dns_name_t *origin, unsigned int options)
1677 {
1678 	isc_result_t result;
1679 	isc_buffer_t buf;
1680 	dns_fixedname_t fn;
1681 	dns_name_t *name;
1682 
1683 	REQUIRE(src != NULL);
1684 
1685 	isc_buffer_init(&buf, (void *)src, strlen(src));
1686 	isc_buffer_add(&buf, strlen(src));
1687 	if (BINDABLE(target) && target->buffer != NULL)
1688 		name = target;
1689 	else {
1690 		dns_fixedname_init(&fn);
1691 		name = dns_fixedname_name(&fn);
1692 	}
1693 
1694 	result = dns_name_fromtext(name, &buf, origin, options, NULL);
1695 	if (result != ISC_R_SUCCESS)
1696 		return (result);
1697 
1698 	if (name != target)
1699 		result = dns_name_dupwithoffsets(name, target);
1700 	return (result);
1701 }
1702 
1703 isc_result_t
1704 dns_name_copy(dns_name_t *source, dns_name_t *dest, isc_buffer_t *target) {
1705 	unsigned char *ndata;
1706 
1707 	/*
1708 	 * Make dest a copy of source.
1709 	 */
1710 
1711 	REQUIRE(target != NULL || dest->buffer != NULL);
1712 
1713 	if (target == NULL) {
1714 		target = dest->buffer;
1715 		isc_buffer_clear(dest->buffer);
1716 	}
1717 
1718 	REQUIRE(BINDABLE(dest));
1719 
1720 	/*
1721 	 * Set up.
1722 	 */
1723 	if (target->length - target->used < source->length)
1724 		return (ISC_R_NOSPACE);
1725 
1726 	ndata = (unsigned char *)target->base + target->used;
1727 	dest->ndata = target->base;
1728 
1729 	if (source->length != 0)
1730 		memmove(ndata, source->ndata, source->length);
1731 
1732 	dest->ndata = ndata;
1733 	dest->labels = source->labels;
1734 	dest->length = source->length;
1735 	if ((source->attributes & DNS_NAMEATTR_ABSOLUTE) != 0)
1736 		dest->attributes = DNS_NAMEATTR_ABSOLUTE;
1737 	else
1738 		dest->attributes = 0;
1739 
1740 	if (dest->labels > 0 && dest->offsets != NULL) {
1741 		if (source->offsets != NULL)
1742 			memmove(dest->offsets, source->offsets, source->labels);
1743 		else
1744 			set_offsets(dest, dest->offsets, NULL);
1745 	}
1746 
1747 	isc_buffer_add(target, dest->length);
1748 
1749 	return (ISC_R_SUCCESS);
1750 }
1751