xref: /openbsd-src/usr.bin/dig/lib/dns/name.c (revision 99fd087599a8791921855f21bd7e36130f39aadc)
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.13 2020/02/25 05:00:42 jsg 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 isc_boolean_t
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 (ISC_TRUE);
221 	return (ISC_FALSE);
222 }
223 
224 unsigned int
225 dns_name_hash(dns_name_t *name, isc_boolean_t 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 isc_boolean_t
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 (ISC_TRUE);
423 
424 	if (name1->length != name2->length)
425 		return (ISC_FALSE);
426 
427 	l = name1->labels;
428 
429 	if (l != name2->labels)
430 		return (ISC_FALSE);
431 
432 	label1 = name1->ndata;
433 	label2 = name2->ndata;
434 	while (l-- > 0) {
435 		count = *label1++;
436 		if (count != *label2++)
437 			return (ISC_FALSE);
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 (ISC_FALSE);
446 			c = maptolower[label1[1]];
447 			if (c != maptolower[label2[1]])
448 				return (ISC_FALSE);
449 			c = maptolower[label1[2]];
450 			if (c != maptolower[label2[2]])
451 				return (ISC_FALSE);
452 			c = maptolower[label1[3]];
453 			if (c != maptolower[label2[3]])
454 				return (ISC_FALSE);
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 (ISC_FALSE);
463 		}
464 	}
465 
466 	return (ISC_TRUE);
467 }
468 
469 isc_boolean_t
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 (ISC_FALSE);
489 
490 	if (memcmp(name1->ndata, name2->ndata, name1->length) != 0)
491 		return (ISC_FALSE);
492 
493 	return (ISC_TRUE);
494 }
495 
496 isc_boolean_t
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 (ISC_TRUE);
515 
516 	return (ISC_FALSE);
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 	isc_boolean_t done;
695 	unsigned char *offsets;
696 	dns_offsets_t odata;
697 	isc_boolean_t 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 = ISC_TF((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 = ISC_FALSE;
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 = ISC_TRUE;
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 = ISC_TRUE;
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, isc_boolean_t 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 	isc_boolean_t saw_root = ISC_FALSE;
943 	isc_boolean_t omit_final_dot =
944 		ISC_TF(options & DNS_NAME_OMITFINALDOT);
945 
946 	/*
947 	 * This function assumes the name is in proper uncompressed
948 	 * wire format.
949 	 */
950 
951 	ndata = name->ndata;
952 	nlen = name->length;
953 	labels = name->labels;
954 	tdata = isc_buffer_used(target);
955 	tlen = isc_buffer_availablelength(target);
956 
957 	trem = tlen;
958 
959 	if (labels == 0 && nlen == 0) {
960 		/*
961 		 * Special handling for an empty name.
962 		 */
963 		if (trem == 0)
964 			return (ISC_R_NOSPACE);
965 
966 		/*
967 		 * The names of these booleans are misleading in this case.
968 		 * This empty name is not necessarily from the root node of
969 		 * the DNS root zone, nor is a final dot going to be included.
970 		 * They need to be set this way, though, to keep the "@"
971 		 * from being trounced.
972 		 */
973 		saw_root = ISC_TRUE;
974 		omit_final_dot = ISC_FALSE;
975 		*tdata++ = '@';
976 		trem--;
977 
978 		/*
979 		 * Skip the while() loop.
980 		 */
981 		nlen = 0;
982 	} else if (nlen == 1 && labels == 1 && *ndata == '\0') {
983 		/*
984 		 * Special handling for the root label.
985 		 */
986 		if (trem == 0)
987 			return (ISC_R_NOSPACE);
988 
989 		saw_root = ISC_TRUE;
990 		omit_final_dot = ISC_FALSE;
991 		*tdata++ = '.';
992 		trem--;
993 
994 		/*
995 		 * Skip the while() loop.
996 		 */
997 		nlen = 0;
998 	}
999 
1000 	while (labels > 0 && nlen > 0 && trem > 0) {
1001 		labels--;
1002 		count = *ndata++;
1003 		nlen--;
1004 		if (count == 0) {
1005 			saw_root = ISC_TRUE;
1006 			break;
1007 		}
1008 		if (count < 64) {
1009 			INSIST(nlen >= count);
1010 			while (count > 0) {
1011 				c = *ndata;
1012 				switch (c) {
1013 				/* Special modifiers in zone files. */
1014 				case 0x40: /* '@' */
1015 				case 0x24: /* '$' */
1016 					if ((options & DNS_NAME_MASTERFILE) == 0)
1017 						goto no_escape;
1018 					/* FALLTHROUGH */
1019 				case 0x22: /* '"' */
1020 				case 0x28: /* '(' */
1021 				case 0x29: /* ')' */
1022 				case 0x2E: /* '.' */
1023 				case 0x3B: /* ';' */
1024 				case 0x5C: /* '\\' */
1025 					if (trem < 2)
1026 						return (ISC_R_NOSPACE);
1027 					*tdata++ = '\\';
1028 					CONVERTFROMASCII(c);
1029 					*tdata++ = c;
1030 					ndata++;
1031 					trem -= 2;
1032 					nlen--;
1033 					break;
1034 				no_escape:
1035 				default:
1036 					if (c > 0x20 && c < 0x7f) {
1037 						if (trem == 0)
1038 							return (ISC_R_NOSPACE);
1039 						CONVERTFROMASCII(c);
1040 						*tdata++ = c;
1041 						ndata++;
1042 						trem--;
1043 						nlen--;
1044 					} else {
1045 						if (trem < 4)
1046 							return (ISC_R_NOSPACE);
1047 						*tdata++ = 0x5c;
1048 						*tdata++ = 0x30 +
1049 							   ((c / 100) % 10);
1050 						*tdata++ = 0x30 +
1051 							   ((c / 10) % 10);
1052 						*tdata++ = 0x30 + (c % 10);
1053 						trem -= 4;
1054 						ndata++;
1055 						nlen--;
1056 					}
1057 				}
1058 				count--;
1059 			}
1060 		} else {
1061 			FATAL_ERROR(__FILE__, __LINE__,
1062 				    "Unexpected label type %02x", count);
1063 			/* NOTREACHED */
1064 		}
1065 
1066 		/*
1067 		 * The following assumes names are absolute.  If not, we
1068 		 * fix things up later.  Note that this means that in some
1069 		 * cases one more byte of text buffer is required than is
1070 		 * needed in the final output.
1071 		 */
1072 		if (trem == 0)
1073 			return (ISC_R_NOSPACE);
1074 		*tdata++ = '.';
1075 		trem--;
1076 	}
1077 
1078 	if (nlen != 0 && trem == 0)
1079 		return (ISC_R_NOSPACE);
1080 
1081 	if (!saw_root || omit_final_dot)
1082 		trem++;
1083 
1084 	isc_buffer_add(target, tlen - trem);
1085 
1086 	return (ISC_R_SUCCESS);
1087 }
1088 
1089 isc_result_t
1090 dns_name_downcase(dns_name_t *source, dns_name_t *name, isc_buffer_t *target) {
1091 	unsigned char *sndata, *ndata;
1092 	unsigned int nlen, count, labels;
1093 	isc_buffer_t buffer;
1094 
1095 	/*
1096 	 * Downcase 'source'.
1097 	 */
1098 
1099 	if (source == name) {
1100 		REQUIRE((name->attributes & DNS_NAMEATTR_READONLY) == 0);
1101 		isc_buffer_init(&buffer, source->ndata, source->length);
1102 		target = &buffer;
1103 		ndata = source->ndata;
1104 	} else {
1105 		REQUIRE(BINDABLE(name));
1106 		if (target == NULL) {
1107 			target = name->buffer;
1108 			isc_buffer_clear(name->buffer);
1109 		}
1110 		ndata = (unsigned char *)target->base + target->used;
1111 		name->ndata = ndata;
1112 	}
1113 
1114 	sndata = source->ndata;
1115 	nlen = source->length;
1116 	labels = source->labels;
1117 
1118 	if (nlen > (target->length - target->used)) {
1119 		MAKE_EMPTY(name);
1120 		return (ISC_R_NOSPACE);
1121 	}
1122 
1123 	while (labels > 0 && nlen > 0) {
1124 		labels--;
1125 		count = *sndata++;
1126 		*ndata++ = count;
1127 		nlen--;
1128 		if (count < 64) {
1129 			INSIST(nlen >= count);
1130 			while (count > 0) {
1131 				*ndata++ = maptolower[(*sndata++)];
1132 				nlen--;
1133 				count--;
1134 			}
1135 		} else {
1136 			FATAL_ERROR(__FILE__, __LINE__,
1137 				    "Unexpected label type %02x", count);
1138 			/* Does not return. */
1139 		}
1140 	}
1141 
1142 	if (source != name) {
1143 		name->labels = source->labels;
1144 		name->length = source->length;
1145 		if ((source->attributes & DNS_NAMEATTR_ABSOLUTE) != 0)
1146 			name->attributes = DNS_NAMEATTR_ABSOLUTE;
1147 		else
1148 			name->attributes = 0;
1149 		if (name->labels > 0 && name->offsets != NULL)
1150 			set_offsets(name, name->offsets, NULL);
1151 	}
1152 
1153 	isc_buffer_add(target, name->length);
1154 
1155 	return (ISC_R_SUCCESS);
1156 }
1157 
1158 static void
1159 set_offsets(const dns_name_t *name, unsigned char *offsets,
1160 	    dns_name_t *set_name)
1161 {
1162 	unsigned int offset, count, length, nlabels;
1163 	unsigned char *ndata;
1164 	isc_boolean_t absolute;
1165 
1166 	ndata = name->ndata;
1167 	length = name->length;
1168 	offset = 0;
1169 	nlabels = 0;
1170 	absolute = ISC_FALSE;
1171 	while (offset != length) {
1172 		INSIST(nlabels < 128);
1173 		offsets[nlabels++] = offset;
1174 		count = *ndata++;
1175 		offset++;
1176 		INSIST(count <= 63);
1177 		offset += count;
1178 		ndata += count;
1179 		INSIST(offset <= length);
1180 		if (count == 0) {
1181 			absolute = ISC_TRUE;
1182 			break;
1183 		}
1184 	}
1185 	if (set_name != NULL) {
1186 		INSIST(set_name == name);
1187 
1188 		set_name->labels = nlabels;
1189 		set_name->length = offset;
1190 		if (absolute)
1191 			set_name->attributes |= DNS_NAMEATTR_ABSOLUTE;
1192 		else
1193 			set_name->attributes &= ~DNS_NAMEATTR_ABSOLUTE;
1194 	}
1195 	INSIST(nlabels == name->labels);
1196 	INSIST(offset == name->length);
1197 }
1198 
1199 isc_result_t
1200 dns_name_fromwire(dns_name_t *name, isc_buffer_t *source,
1201 		  dns_decompress_t *dctx, unsigned int options,
1202 		  isc_buffer_t *target)
1203 {
1204 	unsigned char *cdata, *ndata;
1205 	unsigned int cused; /* Bytes of compressed name data used */
1206 	unsigned int nused, labels, n, nmax;
1207 	unsigned int current, new_current, biggest_pointer;
1208 	isc_boolean_t done;
1209 	fw_state state = fw_start;
1210 	unsigned int c;
1211 	unsigned char *offsets;
1212 	dns_offsets_t odata;
1213 	isc_boolean_t downcase;
1214 	isc_boolean_t seen_pointer;
1215 
1216 	/*
1217 	 * Copy the possibly-compressed name at source into target,
1218 	 * decompressing it.  Loop prevention is performed by checking
1219 	 * the new pointer against biggest_pointer.
1220 	 */
1221 
1222 	downcase = ISC_TF((options & DNS_NAME_DOWNCASE) != 0);
1223 
1224 	if (target == NULL && name->buffer != NULL) {
1225 		target = name->buffer;
1226 		isc_buffer_clear(target);
1227 	}
1228 
1229 	REQUIRE(dctx != NULL);
1230 	REQUIRE(BINDABLE(name));
1231 
1232 	INIT_OFFSETS(name, offsets, odata);
1233 
1234 	/*
1235 	 * Make 'name' empty in case of failure.
1236 	 */
1237 	MAKE_EMPTY(name);
1238 
1239 	/*
1240 	 * Initialize things to make the compiler happy; they're not required.
1241 	 */
1242 	n = 0;
1243 	new_current = 0;
1244 
1245 	/*
1246 	 * Set up.
1247 	 */
1248 	labels = 0;
1249 	done = ISC_FALSE;
1250 
1251 	ndata = isc_buffer_used(target);
1252 	nused = 0;
1253 	seen_pointer = ISC_FALSE;
1254 
1255 	/*
1256 	 * Find the maximum number of uncompressed target name
1257 	 * bytes we are willing to generate.  This is the smaller
1258 	 * of the available target buffer length and the
1259 	 * maximum legal domain name length (255).
1260 	 */
1261 	nmax = isc_buffer_availablelength(target);
1262 	if (nmax > DNS_NAME_MAXWIRE)
1263 		nmax = DNS_NAME_MAXWIRE;
1264 
1265 	cdata = isc_buffer_current(source);
1266 	cused = 0;
1267 
1268 	current = source->current;
1269 	biggest_pointer = current;
1270 
1271 	/*
1272 	 * Note:  The following code is not optimized for speed, but
1273 	 * rather for correctness.  Speed will be addressed in the future.
1274 	 */
1275 
1276 	while (current < source->active && !done) {
1277 		c = *cdata++;
1278 		current++;
1279 		if (!seen_pointer)
1280 			cused++;
1281 
1282 		switch (state) {
1283 		case fw_start:
1284 			if (c < 64) {
1285 				offsets[labels] = nused;
1286 				labels++;
1287 				if (nused + c + 1 > nmax)
1288 					goto full;
1289 				nused += c + 1;
1290 				*ndata++ = c;
1291 				if (c == 0)
1292 					done = ISC_TRUE;
1293 				n = c;
1294 				state = fw_ordinary;
1295 			} else if (c >= 128 && c < 192) {
1296 				/*
1297 				 * 14 bit local compression pointer.
1298 				 * Local compression is no longer an
1299 				 * IETF draft.
1300 				 */
1301 				return (DNS_R_BADLABELTYPE);
1302 			} else if (c >= 192) {
1303 				/*
1304 				 * Ordinary 14-bit pointer.
1305 				 */
1306 				if ((dctx->allowed & DNS_COMPRESS_GLOBAL14) ==
1307 				    0)
1308 					return (DNS_R_DISALLOWED);
1309 				new_current = c & 0x3F;
1310 				state = fw_newcurrent;
1311 			} else
1312 				return (DNS_R_BADLABELTYPE);
1313 			break;
1314 		case fw_ordinary:
1315 			if (downcase)
1316 				c = maptolower[c];
1317 			*ndata++ = c;
1318 			n--;
1319 			if (n == 0)
1320 				state = fw_start;
1321 			break;
1322 		case fw_newcurrent:
1323 			new_current *= 256;
1324 			new_current += c;
1325 			if (new_current >= biggest_pointer)
1326 				return (DNS_R_BADPOINTER);
1327 			biggest_pointer = new_current;
1328 			current = new_current;
1329 			cdata = (unsigned char *)source->base + current;
1330 			seen_pointer = ISC_TRUE;
1331 			state = fw_start;
1332 			break;
1333 		default:
1334 			FATAL_ERROR(__FILE__, __LINE__,
1335 				    "Unknown state %d", state);
1336 			/* Does not return. */
1337 		}
1338 	}
1339 
1340 	if (!done)
1341 		return (ISC_R_UNEXPECTEDEND);
1342 
1343 	name->ndata = (unsigned char *)target->base + target->used;
1344 	name->labels = labels;
1345 	name->length = nused;
1346 	name->attributes |= DNS_NAMEATTR_ABSOLUTE;
1347 
1348 	isc_buffer_forward(source, cused);
1349 	isc_buffer_add(target, name->length);
1350 
1351 	return (ISC_R_SUCCESS);
1352 
1353  full:
1354 	if (nmax == DNS_NAME_MAXWIRE)
1355 		/*
1356 		 * The name did not fit even though we had a buffer
1357 		 * big enough to fit a maximum-length name.
1358 		 */
1359 		return (DNS_R_NAMETOOLONG);
1360 	else
1361 		/*
1362 		 * The name might fit if only the caller could give us a
1363 		 * big enough buffer.
1364 		 */
1365 		return (ISC_R_NOSPACE);
1366 }
1367 
1368 isc_result_t
1369 dns_name_towire(const dns_name_t *name, dns_compress_t *cctx,
1370 		isc_buffer_t *target)
1371 {
1372 	unsigned int methods;
1373 	uint16_t offset;
1374 	dns_name_t gp;	/* Global compression prefix */
1375 	isc_boolean_t gf;	/* Global compression target found */
1376 	uint16_t go;	/* Global compression offset */
1377 	dns_offsets_t clo;
1378 	dns_name_t clname;
1379 
1380 	/*
1381 	 * Convert 'name' into wire format, compressing it as specified by the
1382 	 * compression context 'cctx', and storing the result in 'target'.
1383 	 */
1384 
1385 	REQUIRE(cctx != NULL);
1386 
1387 	/*
1388 	 * If 'name' doesn't have an offsets table, make a clone which
1389 	 * has one.
1390 	 */
1391 	if (name->offsets == NULL) {
1392 		dns_name_init(&clname, clo);
1393 		dns_name_clone(name, &clname);
1394 		name = &clname;
1395 	}
1396 	dns_name_init(&gp, NULL);
1397 
1398 	offset = target->used;	/*XXX*/
1399 
1400 	methods = dns_compress_getmethods(cctx);
1401 
1402 	if ((name->attributes & DNS_NAMEATTR_NOCOMPRESS) == 0 &&
1403 	    (methods & DNS_COMPRESS_GLOBAL14) != 0)
1404 		gf = dns_compress_findglobal(cctx, name, &gp, &go);
1405 	else
1406 		gf = ISC_FALSE;
1407 
1408 	/*
1409 	 * If the offset is too high for 14 bit global compression, we're
1410 	 * out of luck.
1411 	 */
1412 	if (gf && go >= 0x4000)
1413 		gf = ISC_FALSE;
1414 
1415 	/*
1416 	 * Will the compression pointer reduce the message size?
1417 	 */
1418 	if (gf && (gp.length + 2) >= name->length)
1419 		gf = ISC_FALSE;
1420 
1421 	if (gf) {
1422 		if (target->length - target->used < gp.length)
1423 			return (ISC_R_NOSPACE);
1424 		if (gp.length != 0) {
1425 			unsigned char *base = target->base;
1426 			(void)memmove(base + target->used, gp.ndata,
1427 				      (size_t)gp.length);
1428 		}
1429 		isc_buffer_add(target, gp.length);
1430 		go |= 0xc000;
1431 		if (target->length - target->used < 2)
1432 			return (ISC_R_NOSPACE);
1433 		isc_buffer_putuint16(target, go);
1434 		if (gp.length != 0)
1435 			dns_compress_add(cctx, name, &gp, offset);
1436 	} else {
1437 		if (target->length - target->used < name->length)
1438 			return (ISC_R_NOSPACE);
1439 		if (name->length != 0) {
1440 			unsigned char *base = target->base;
1441 			(void)memmove(base + target->used, name->ndata,
1442 				      (size_t)name->length);
1443 		}
1444 		isc_buffer_add(target, name->length);
1445 		dns_compress_add(cctx, name, name, offset);
1446 	}
1447 	return (ISC_R_SUCCESS);
1448 }
1449 
1450 isc_result_t
1451 dns_name_concatenate(dns_name_t *prefix, dns_name_t *suffix, dns_name_t *name,
1452 		     isc_buffer_t *target)
1453 {
1454 	unsigned char *ndata, *offsets;
1455 	unsigned int nrem, labels, prefix_length, length;
1456 	isc_boolean_t copy_prefix = ISC_TRUE;
1457 	isc_boolean_t copy_suffix = ISC_TRUE;
1458 	isc_boolean_t absolute = ISC_FALSE;
1459 	dns_name_t tmp_name;
1460 	dns_offsets_t odata;
1461 
1462 	/*
1463 	 * Concatenate 'prefix' and 'suffix'.
1464 	 */
1465 
1466 	if (prefix == NULL || prefix->labels == 0)
1467 		copy_prefix = ISC_FALSE;
1468 	if (suffix == NULL || suffix->labels == 0)
1469 		copy_suffix = ISC_FALSE;
1470 	if (copy_prefix &&
1471 	    (prefix->attributes & DNS_NAMEATTR_ABSOLUTE) != 0) {
1472 		absolute = ISC_TRUE;
1473 		REQUIRE(!copy_suffix);
1474 	}
1475 	if (name == NULL) {
1476 		dns_name_init(&tmp_name, odata);
1477 		name = &tmp_name;
1478 	}
1479 	if (target == NULL) {
1480 		INSIST(name->buffer != NULL);
1481 		target = name->buffer;
1482 		isc_buffer_clear(name->buffer);
1483 	}
1484 
1485 	REQUIRE(BINDABLE(name));
1486 
1487 	/*
1488 	 * Set up.
1489 	 */
1490 	nrem = target->length - target->used;
1491 	ndata = (unsigned char *)target->base + target->used;
1492 	if (nrem > DNS_NAME_MAXWIRE)
1493 		nrem = DNS_NAME_MAXWIRE;
1494 	length = 0;
1495 	prefix_length = 0;
1496 	labels = 0;
1497 	if (copy_prefix) {
1498 		prefix_length = prefix->length;
1499 		length += prefix_length;
1500 		labels += prefix->labels;
1501 	}
1502 	if (copy_suffix) {
1503 		length += suffix->length;
1504 		labels += suffix->labels;
1505 	}
1506 	if (length > DNS_NAME_MAXWIRE) {
1507 		MAKE_EMPTY(name);
1508 		return (DNS_R_NAMETOOLONG);
1509 	}
1510 	if (length > nrem) {
1511 		MAKE_EMPTY(name);
1512 		return (ISC_R_NOSPACE);
1513 	}
1514 
1515 	if (copy_suffix) {
1516 		if ((suffix->attributes & DNS_NAMEATTR_ABSOLUTE) != 0)
1517 			absolute = ISC_TRUE;
1518 		memmove(ndata + prefix_length, suffix->ndata, suffix->length);
1519 	}
1520 
1521 	/*
1522 	 * If 'prefix' and 'name' are the same object, and the object has
1523 	 * a dedicated buffer, and we're using it, then we don't have to
1524 	 * copy anything.
1525 	 */
1526 	if (copy_prefix && (prefix != name || prefix->buffer != target))
1527 		memmove(ndata, prefix->ndata, prefix_length);
1528 
1529 	name->ndata = ndata;
1530 	name->labels = labels;
1531 	name->length = length;
1532 	if (absolute)
1533 		name->attributes = DNS_NAMEATTR_ABSOLUTE;
1534 	else
1535 		name->attributes = 0;
1536 
1537 	if (name->labels > 0 && name->offsets != NULL) {
1538 		INIT_OFFSETS(name, offsets, odata);
1539 		set_offsets(name, offsets, NULL);
1540 	}
1541 
1542 	isc_buffer_add(target, name->length);
1543 
1544 	return (ISC_R_SUCCESS);
1545 }
1546 
1547 isc_result_t
1548 dns_name_dup(const dns_name_t *source,
1549 	     dns_name_t *target)
1550 {
1551 	/*
1552 	 * Make 'target' a dynamically allocated copy of 'source'.
1553 	 */
1554 
1555 	REQUIRE(source->length > 0);
1556 	REQUIRE(BINDABLE(target));
1557 
1558 	/*
1559 	 * Make 'target' empty in case of failure.
1560 	 */
1561 	MAKE_EMPTY(target);
1562 
1563 	target->ndata = malloc(source->length);
1564 	if (target->ndata == NULL)
1565 		return (ISC_R_NOMEMORY);
1566 
1567 	memmove(target->ndata, source->ndata, source->length);
1568 
1569 	target->length = source->length;
1570 	target->labels = source->labels;
1571 	target->attributes = DNS_NAMEATTR_DYNAMIC;
1572 	if ((source->attributes & DNS_NAMEATTR_ABSOLUTE) != 0)
1573 		target->attributes |= DNS_NAMEATTR_ABSOLUTE;
1574 	if (target->offsets != NULL) {
1575 		if (source->offsets != NULL)
1576 			memmove(target->offsets, source->offsets,
1577 				source->labels);
1578 		else
1579 			set_offsets(target, target->offsets, NULL);
1580 	}
1581 
1582 	return (ISC_R_SUCCESS);
1583 }
1584 
1585 isc_result_t
1586 dns_name_dupwithoffsets(dns_name_t *source,
1587 			dns_name_t *target)
1588 {
1589 	/*
1590 	 * Make 'target' a read-only dynamically allocated copy of 'source'.
1591 	 * 'target' will also have a dynamically allocated offsets table.
1592 	 */
1593 
1594 	REQUIRE(source->length > 0);
1595 	REQUIRE(BINDABLE(target));
1596 	REQUIRE(target->offsets == NULL);
1597 
1598 	/*
1599 	 * Make 'target' empty in case of failure.
1600 	 */
1601 	MAKE_EMPTY(target);
1602 
1603 	target->ndata = malloc(source->length + source->labels);
1604 	if (target->ndata == NULL)
1605 		return (ISC_R_NOMEMORY);
1606 
1607 	memmove(target->ndata, source->ndata, source->length);
1608 
1609 	target->length = source->length;
1610 	target->labels = source->labels;
1611 	target->attributes = DNS_NAMEATTR_DYNAMIC | DNS_NAMEATTR_DYNOFFSETS |
1612 		DNS_NAMEATTR_READONLY;
1613 	if ((source->attributes & DNS_NAMEATTR_ABSOLUTE) != 0)
1614 		target->attributes |= DNS_NAMEATTR_ABSOLUTE;
1615 	target->offsets = target->ndata + source->length;
1616 	if (source->offsets != NULL)
1617 		memmove(target->offsets, source->offsets, source->labels);
1618 	else
1619 		set_offsets(target, target->offsets, NULL);
1620 
1621 	return (ISC_R_SUCCESS);
1622 }
1623 
1624 void
1625 dns_name_free(dns_name_t *name) {
1626 	/*
1627 	 * Free 'name'.
1628 	 */
1629 
1630 	REQUIRE((name->attributes & DNS_NAMEATTR_DYNAMIC) != 0);
1631 
1632 	free(name->ndata);
1633 	dns_name_invalidate(name);
1634 }
1635 
1636 isc_boolean_t
1637 dns_name_dynamic(dns_name_t *name) {
1638 
1639 	/*
1640 	 * Returns whether there is dynamic memory associated with this name.
1641 	 */
1642 
1643 	return ((name->attributes & DNS_NAMEATTR_DYNAMIC) != 0 ?
1644 		ISC_TRUE : ISC_FALSE);
1645 }
1646 
1647 void
1648 dns_name_format(dns_name_t *name, char *cp, unsigned int size) {
1649 	isc_result_t result;
1650 	isc_buffer_t buf;
1651 
1652 	REQUIRE(size > 0);
1653 
1654 	/*
1655 	 * Leave room for null termination after buffer.
1656 	 */
1657 	isc_buffer_init(&buf, cp, size - 1);
1658 	result = dns_name_totext(name, ISC_TRUE, &buf);
1659 	if (result == ISC_R_SUCCESS) {
1660 		/*
1661 		 * Null terminate.
1662 		 */
1663 		isc_region_t r;
1664 		isc_buffer_usedregion(&buf, &r);
1665 		((char *) r.base)[r.length] = '\0';
1666 
1667 	} else
1668 		snprintf(cp, size, "<unknown>");
1669 }
1670 
1671 /*
1672  * dns_name_fromstring() -- convert directly from a string to a name,
1673  * allocating memory as needed
1674  */
1675 isc_result_t
1676 dns_name_fromstring2(dns_name_t *target, const char *src,
1677 		     const dns_name_t *origin, unsigned int options)
1678 {
1679 	isc_result_t result;
1680 	isc_buffer_t buf;
1681 	dns_fixedname_t fn;
1682 	dns_name_t *name;
1683 
1684 	REQUIRE(src != NULL);
1685 
1686 	isc_buffer_init(&buf, (void *)src, strlen(src));
1687 	isc_buffer_add(&buf, strlen(src));
1688 	if (BINDABLE(target) && target->buffer != NULL)
1689 		name = target;
1690 	else {
1691 		dns_fixedname_init(&fn);
1692 		name = dns_fixedname_name(&fn);
1693 	}
1694 
1695 	result = dns_name_fromtext(name, &buf, origin, options, NULL);
1696 	if (result != ISC_R_SUCCESS)
1697 		return (result);
1698 
1699 	if (name != target)
1700 		result = dns_name_dupwithoffsets(name, target);
1701 	return (result);
1702 }
1703 
1704 isc_result_t
1705 dns_name_copy(dns_name_t *source, dns_name_t *dest, isc_buffer_t *target) {
1706 	unsigned char *ndata;
1707 
1708 	/*
1709 	 * Make dest a copy of source.
1710 	 */
1711 
1712 	REQUIRE(target != NULL || dest->buffer != NULL);
1713 
1714 	if (target == NULL) {
1715 		target = dest->buffer;
1716 		isc_buffer_clear(dest->buffer);
1717 	}
1718 
1719 	REQUIRE(BINDABLE(dest));
1720 
1721 	/*
1722 	 * Set up.
1723 	 */
1724 	if (target->length - target->used < source->length)
1725 		return (ISC_R_NOSPACE);
1726 
1727 	ndata = (unsigned char *)target->base + target->used;
1728 	dest->ndata = target->base;
1729 
1730 	if (source->length != 0)
1731 		memmove(ndata, source->ndata, source->length);
1732 
1733 	dest->ndata = ndata;
1734 	dest->labels = source->labels;
1735 	dest->length = source->length;
1736 	if ((source->attributes & DNS_NAMEATTR_ABSOLUTE) != 0)
1737 		dest->attributes = DNS_NAMEATTR_ABSOLUTE;
1738 	else
1739 		dest->attributes = 0;
1740 
1741 	if (dest->labels > 0 && dest->offsets != NULL) {
1742 		if (source->offsets != NULL)
1743 			memmove(dest->offsets, source->offsets, source->labels);
1744 		else
1745 			set_offsets(dest, dest->offsets, NULL);
1746 	}
1747 
1748 	isc_buffer_add(target, dest->length);
1749 
1750 	return (ISC_R_SUCCESS);
1751 }
1752