Remove building with NOCRYPTO option
[minix.git] / external / bsd / bind / dist / lib / dns / name.c
blob72d59d37c750372edf8b80b76a172a8500f41261
1 /* $NetBSD: name.c,v 1.11 2015/07/08 17:28:58 christos Exp $ */
3 /*
4 * Copyright (C) 2004-2014 Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (C) 1998-2003 Internet Software Consortium.
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
20 /* Id */
22 /*! \file */
24 #include <config.h>
26 #include <ctype.h>
27 #include <stdlib.h>
29 #include <isc/buffer.h>
30 #include <isc/hash.h>
31 #include <isc/mem.h>
32 #include <isc/once.h>
33 #include <isc/print.h>
34 #include <isc/string.h>
35 #include <isc/thread.h>
36 #include <isc/util.h>
38 #include <dns/compress.h>
39 #include <dns/fixedname.h>
40 #include <dns/name.h>
41 #include <dns/result.h>
43 #define VALID_NAME(n) ISC_MAGIC_VALID(n, DNS_NAME_MAGIC)
45 typedef enum {
46 ft_init = 0,
47 ft_start,
48 ft_ordinary,
49 ft_initialescape,
50 ft_escape,
51 ft_escdecimal,
52 ft_at
53 } ft_state;
55 typedef enum {
56 fw_start = 0,
57 fw_ordinary,
58 fw_newcurrent
59 } fw_state;
61 static char digitvalue[256] = {
62 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*16*/
63 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*32*/
64 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*48*/
65 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, /*64*/
66 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*80*/
67 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*96*/
68 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*112*/
69 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*128*/
70 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
71 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
72 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
73 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
74 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
75 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
76 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
77 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*256*/
80 static unsigned char maptolower[] = {
81 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
82 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
83 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
84 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
85 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
86 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
87 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
88 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
89 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
90 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
91 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
92 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
93 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
94 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
95 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
96 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
97 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
98 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
99 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
100 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
101 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
102 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
103 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
104 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
105 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
106 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
107 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
108 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
109 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
110 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
111 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
112 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
115 #define CONVERTTOASCII(c)
116 #define CONVERTFROMASCII(c)
118 #define INIT_OFFSETS(name, var, default) \
119 if (name->offsets != NULL) \
120 var = name->offsets; \
121 else \
122 var = default;
124 #define SETUP_OFFSETS(name, var, default) \
125 if (name->offsets != NULL) \
126 var = name->offsets; \
127 else { \
128 var = default; \
129 set_offsets(name, var, NULL); \
133 * Note: If additional attributes are added that should not be set for
134 * empty names, MAKE_EMPTY() must be changed so it clears them.
136 #define MAKE_EMPTY(name) \
137 do { \
138 name->ndata = NULL; \
139 name->length = 0; \
140 name->labels = 0; \
141 name->attributes &= ~DNS_NAMEATTR_ABSOLUTE; \
142 } while (/*CONSTCOND*/0);
145 * A name is "bindable" if it can be set to point to a new value, i.e.
146 * name->ndata and name->length may be changed.
148 #define BINDABLE(name) \
149 ((name->attributes & (DNS_NAMEATTR_READONLY|DNS_NAMEATTR_DYNAMIC)) \
150 == 0)
153 * Note that the name data must be a char array, not a string
154 * literal, to avoid compiler warnings about discarding
155 * the const attribute of a string.
157 static unsigned char root_ndata[] = { '\0' };
158 static unsigned char root_offsets[] = { 0 };
160 static dns_name_t root =
162 DNS_NAME_MAGIC,
163 root_ndata, 1, 1,
164 DNS_NAMEATTR_READONLY | DNS_NAMEATTR_ABSOLUTE,
165 root_offsets, NULL,
166 {(void *)-1, (void *)-1},
167 {NULL, NULL}
170 /* XXXDCL make const? */
171 LIBDNS_EXTERNAL_DATA dns_name_t *dns_rootname = &root;
173 static unsigned char wild_ndata[] = { '\001', '*' };
174 static unsigned char wild_offsets[] = { 0 };
176 static dns_name_t wild =
178 DNS_NAME_MAGIC,
179 wild_ndata, 2, 1,
180 DNS_NAMEATTR_READONLY,
181 wild_offsets, NULL,
182 {(void *)-1, (void *)-1},
183 {NULL, NULL}
186 /* XXXDCL make const? */
187 LIBDNS_EXTERNAL_DATA dns_name_t *dns_wildcardname = &wild;
189 unsigned int
190 dns_fullname_hash(dns_name_t *name, isc_boolean_t case_sensitive);
193 * dns_name_t to text post-conversion procedure.
195 #ifdef ISC_PLATFORM_USETHREADS
196 static int thread_key_initialized = 0;
197 static isc_mutex_t thread_key_mutex;
198 static isc_mem_t *thread_key_mctx = NULL;
199 static isc_thread_key_t totext_filter_proc_key;
200 static isc_once_t once = ISC_ONCE_INIT;
201 #else
202 static dns_name_totextfilter_t totext_filter_proc = NULL;
203 #endif
205 static void
206 set_offsets(const dns_name_t *name, unsigned char *offsets,
207 dns_name_t *set_name);
209 void
210 dns_name_init(dns_name_t *name, unsigned char *offsets) {
212 * Initialize 'name'.
214 DNS_NAME_INIT(name, offsets);
217 void
218 dns_name_reset(dns_name_t *name) {
219 REQUIRE(VALID_NAME(name));
220 REQUIRE(BINDABLE(name));
222 DNS_NAME_RESET(name);
225 void
226 dns_name_invalidate(dns_name_t *name) {
228 * Make 'name' invalid.
231 REQUIRE(VALID_NAME(name));
233 name->magic = 0;
234 name->ndata = NULL;
235 name->length = 0;
236 name->labels = 0;
237 name->attributes = 0;
238 name->offsets = NULL;
239 name->buffer = NULL;
240 ISC_LINK_INIT(name, link);
243 isc_boolean_t
244 dns_name_isvalid(const dns_name_t *name) {
245 unsigned char *ndata, *offsets;
246 unsigned int offset, count, length, nlabels;
248 if (!VALID_NAME(name))
249 return (ISC_FALSE);
251 if (name->length > 255U || name->labels > 127U)
252 return (ISC_FALSE);
254 ndata = name->ndata;
255 length = name->length;
256 offsets = name->offsets;
257 offset = 0;
258 nlabels = 0;
260 while (offset != length) {
261 count = *ndata;
262 if (count > 63U)
263 return (ISC_FALSE);
264 if (offsets != NULL && offsets[nlabels] != offset)
265 return (ISC_FALSE);
267 nlabels++;
268 offset += count + 1;
269 ndata += count + 1;
270 if (offset > length)
271 return (ISC_FALSE);
273 if (count == 0)
274 break;
277 if (nlabels != name->labels || offset != name->length)
278 return (ISC_FALSE);
280 return (ISC_TRUE);
283 void
284 dns_name_setbuffer(dns_name_t *name, isc_buffer_t *buffer) {
286 * Dedicate a buffer for use with 'name'.
289 REQUIRE(VALID_NAME(name));
290 REQUIRE((buffer != NULL && name->buffer == NULL) ||
291 (buffer == NULL));
293 name->buffer = buffer;
296 isc_boolean_t
297 dns_name_hasbuffer(const dns_name_t *name) {
299 * Does 'name' have a dedicated buffer?
302 REQUIRE(VALID_NAME(name));
304 if (name->buffer != NULL)
305 return (ISC_TRUE);
307 return (ISC_FALSE);
310 isc_boolean_t
311 dns_name_isabsolute(const dns_name_t *name) {
314 * Does 'name' end in the root label?
317 REQUIRE(VALID_NAME(name));
319 if ((name->attributes & DNS_NAMEATTR_ABSOLUTE) != 0)
320 return (ISC_TRUE);
321 return (ISC_FALSE);
324 #define hyphenchar(c) ((c) == 0x2d)
325 #define asterchar(c) ((c) == 0x2a)
326 #define alphachar(c) (((c) >= 0x41 && (c) <= 0x5a) \
327 || ((c) >= 0x61 && (c) <= 0x7a))
328 #define digitchar(c) ((c) >= 0x30 && (c) <= 0x39)
329 #define borderchar(c) (alphachar(c) || digitchar(c))
330 #define middlechar(c) (borderchar(c) || hyphenchar(c))
331 #define domainchar(c) ((c) > 0x20 && (c) < 0x7f)
333 isc_boolean_t
334 dns_name_ismailbox(const dns_name_t *name) {
335 unsigned char *ndata, ch;
336 unsigned int n;
337 isc_boolean_t first;
339 REQUIRE(VALID_NAME(name));
340 REQUIRE(name->labels > 0);
341 REQUIRE(name->attributes & DNS_NAMEATTR_ABSOLUTE);
344 * Root label.
346 if (name->length == 1)
347 return (ISC_TRUE);
349 ndata = name->ndata;
350 n = *ndata++;
351 INSIST(n <= 63);
352 while (n--) {
353 ch = *ndata++;
354 if (!domainchar(ch))
355 return (ISC_FALSE);
358 if (ndata == name->ndata + name->length)
359 return (ISC_FALSE);
362 * RFC952/RFC1123 hostname.
364 while (ndata < (name->ndata + name->length)) {
365 n = *ndata++;
366 INSIST(n <= 63);
367 first = ISC_TRUE;
368 while (n--) {
369 ch = *ndata++;
370 if (first || n == 0) {
371 if (!borderchar(ch))
372 return (ISC_FALSE);
373 } else {
374 if (!middlechar(ch))
375 return (ISC_FALSE);
377 first = ISC_FALSE;
380 return (ISC_TRUE);
383 isc_boolean_t
384 dns_name_ishostname(const dns_name_t *name, isc_boolean_t wildcard) {
385 unsigned char *ndata, ch;
386 unsigned int n;
387 isc_boolean_t first;
389 REQUIRE(VALID_NAME(name));
390 REQUIRE(name->labels > 0);
391 REQUIRE(name->attributes & DNS_NAMEATTR_ABSOLUTE);
394 * Root label.
396 if (name->length == 1)
397 return (ISC_TRUE);
400 * Skip wildcard if this is a ownername.
402 ndata = name->ndata;
403 if (wildcard && ndata[0] == 1 && ndata[1] == '*')
404 ndata += 2;
407 * RFC292/RFC1123 hostname.
409 while (ndata < (name->ndata + name->length)) {
410 n = *ndata++;
411 INSIST(n <= 63);
412 first = ISC_TRUE;
413 while (n--) {
414 ch = *ndata++;
415 if (first || n == 0) {
416 if (!borderchar(ch))
417 return (ISC_FALSE);
418 } else {
419 if (!middlechar(ch))
420 return (ISC_FALSE);
422 first = ISC_FALSE;
425 return (ISC_TRUE);
428 isc_boolean_t
429 dns_name_iswildcard(const dns_name_t *name) {
430 unsigned char *ndata;
433 * Is 'name' a wildcard name?
436 REQUIRE(VALID_NAME(name));
437 REQUIRE(name->labels > 0);
439 if (name->length >= 2) {
440 ndata = name->ndata;
441 if (ndata[0] == 1 && ndata[1] == '*')
442 return (ISC_TRUE);
445 return (ISC_FALSE);
448 isc_boolean_t
449 dns_name_internalwildcard(const dns_name_t *name) {
450 unsigned char *ndata;
451 unsigned int count;
452 unsigned int label;
455 * Does 'name' contain a internal wildcard?
458 REQUIRE(VALID_NAME(name));
459 REQUIRE(name->labels > 0);
462 * Skip first label.
464 ndata = name->ndata;
465 count = *ndata++;
466 INSIST(count <= 63);
467 ndata += count;
468 label = 1;
470 * Check all but the last of the remaining labels.
472 while (label + 1 < name->labels) {
473 count = *ndata++;
474 INSIST(count <= 63);
475 if (count == 1 && *ndata == '*')
476 return (ISC_TRUE);
477 ndata += count;
478 label++;
480 return (ISC_FALSE);
483 static inline unsigned int
484 name_hash(dns_name_t *name, isc_boolean_t case_sensitive) {
485 unsigned int length;
486 const unsigned char *s;
487 unsigned int h = 0;
488 unsigned char c;
490 length = name->length;
491 if (length > 16)
492 length = 16;
495 * This hash function is similar to the one Ousterhout
496 * uses in Tcl.
498 s = name->ndata;
499 if (case_sensitive) {
500 while (length > 0) {
501 h += ( h << 3 ) + *s;
502 s++;
503 length--;
505 } else {
506 while (length > 0) {
507 c = maptolower[*s];
508 h += ( h << 3 ) + c;
509 s++;
510 length--;
514 return (h);
517 unsigned int
518 dns_name_hash(dns_name_t *name, isc_boolean_t case_sensitive) {
520 * Provide a hash value for 'name'.
522 REQUIRE(VALID_NAME(name));
524 if (name->labels == 0)
525 return (0);
527 return (name_hash(name, case_sensitive));
530 unsigned int
531 dns_name_fullhash(dns_name_t *name, isc_boolean_t case_sensitive) {
533 * Provide a hash value for 'name'.
535 REQUIRE(VALID_NAME(name));
537 if (name->labels == 0)
538 return (0);
540 return (isc_hash_calc((const unsigned char *)name->ndata,
541 name->length, case_sensitive));
544 unsigned int
545 dns_fullname_hash(dns_name_t *name, isc_boolean_t case_sensitive) {
547 * This function was deprecated due to the breakage of the name space
548 * convention. We only keep this internally to provide binary backward
549 * compatibility.
551 REQUIRE(VALID_NAME(name));
553 return (dns_name_fullhash(name, case_sensitive));
556 unsigned int
557 dns_name_hashbylabel(dns_name_t *name, isc_boolean_t case_sensitive) {
558 unsigned char *offsets;
559 dns_offsets_t odata;
560 dns_name_t tname;
561 unsigned int h = 0;
562 unsigned int i;
565 * Provide a hash value for 'name'.
567 REQUIRE(VALID_NAME(name));
569 if (name->labels == 0)
570 return (0);
571 else if (name->labels == 1)
572 return (name_hash(name, case_sensitive));
574 SETUP_OFFSETS(name, offsets, odata);
575 DNS_NAME_INIT(&tname, NULL);
576 tname.labels = 1;
577 h = 0;
578 for (i = 0; i < name->labels; i++) {
579 tname.ndata = name->ndata + offsets[i];
580 if (i == name->labels - 1)
581 tname.length = name->length - offsets[i];
582 else
583 tname.length = offsets[i + 1] - offsets[i];
584 h += name_hash(&tname, case_sensitive);
587 return (h);
590 dns_namereln_t
591 dns_name_fullcompare(const dns_name_t *name1, const dns_name_t *name2,
592 int *orderp, unsigned int *nlabelsp)
594 unsigned int l1, l2, l, count1, count2, count, nlabels;
595 int cdiff, ldiff, chdiff;
596 unsigned char *label1, *label2;
597 unsigned char *offsets1, *offsets2;
598 dns_offsets_t odata1, odata2;
599 dns_namereln_t namereln = dns_namereln_none;
602 * Determine the relative ordering under the DNSSEC order relation of
603 * 'name1' and 'name2', and also determine the hierarchical
604 * relationship of the names.
606 * Note: It makes no sense for one of the names to be relative and the
607 * other absolute. If both names are relative, then to be meaningfully
608 * compared the caller must ensure that they are both relative to the
609 * same domain.
612 REQUIRE(VALID_NAME(name1));
613 REQUIRE(VALID_NAME(name2));
614 REQUIRE(orderp != NULL);
615 REQUIRE(nlabelsp != NULL);
617 * Either name1 is absolute and name2 is absolute, or neither is.
619 REQUIRE((name1->attributes & DNS_NAMEATTR_ABSOLUTE) ==
620 (name2->attributes & DNS_NAMEATTR_ABSOLUTE));
622 if (name1 == name2) {
623 *orderp = 0;
624 *nlabelsp = name1->labels;
625 return (dns_namereln_equal);
628 SETUP_OFFSETS(name1, offsets1, odata1);
629 SETUP_OFFSETS(name2, offsets2, odata2);
631 nlabels = 0;
632 l1 = name1->labels;
633 l2 = name2->labels;
634 if (l2 > l1) {
635 l = l1;
636 ldiff = 0 - (l2 - l1);
637 } else {
638 l = l2;
639 ldiff = l1 - l2;
642 while (l > 0) {
643 l--;
644 l1--;
645 l2--;
646 label1 = &name1->ndata[offsets1[l1]];
647 label2 = &name2->ndata[offsets2[l2]];
648 count1 = *label1++;
649 count2 = *label2++;
652 * We dropped bitstring labels, and we don't support any
653 * other extended label types.
655 INSIST(count1 <= 63 && count2 <= 63);
657 cdiff = (int)count1 - (int)count2;
658 if (cdiff < 0)
659 count = count1;
660 else
661 count = count2;
663 while (count > 0) {
664 chdiff = (int)maptolower[*label1] -
665 (int)maptolower[*label2];
666 if (chdiff != 0) {
667 *orderp = chdiff;
668 goto done;
670 count--;
671 label1++;
672 label2++;
674 if (cdiff != 0) {
675 *orderp = cdiff;
676 goto done;
678 nlabels++;
681 *orderp = ldiff;
682 if (ldiff < 0)
683 namereln = dns_namereln_contains;
684 else if (ldiff > 0)
685 namereln = dns_namereln_subdomain;
686 else
687 namereln = dns_namereln_equal;
689 done:
690 *nlabelsp = nlabels;
692 if (nlabels > 0 && namereln == dns_namereln_none)
693 namereln = dns_namereln_commonancestor;
695 return (namereln);
699 dns_name_compare(const dns_name_t *name1, const dns_name_t *name2) {
700 int order;
701 unsigned int nlabels;
704 * Determine the relative ordering under the DNSSEC order relation of
705 * 'name1' and 'name2'.
707 * Note: It makes no sense for one of the names to be relative and the
708 * other absolute. If both names are relative, then to be meaningfully
709 * compared the caller must ensure that they are both relative to the
710 * same domain.
713 (void)dns_name_fullcompare(name1, name2, &order, &nlabels);
715 return (order);
718 isc_boolean_t
719 dns_name_equal(const dns_name_t *name1, const dns_name_t *name2) {
720 unsigned int l, count;
721 unsigned char c;
722 unsigned char *label1, *label2;
725 * Are 'name1' and 'name2' equal?
727 * Note: It makes no sense for one of the names to be relative and the
728 * other absolute. If both names are relative, then to be meaningfully
729 * compared the caller must ensure that they are both relative to the
730 * same domain.
733 REQUIRE(VALID_NAME(name1));
734 REQUIRE(VALID_NAME(name2));
736 * Either name1 is absolute and name2 is absolute, or neither is.
738 REQUIRE((name1->attributes & DNS_NAMEATTR_ABSOLUTE) ==
739 (name2->attributes & DNS_NAMEATTR_ABSOLUTE));
741 if (name1 == name2)
742 return (ISC_TRUE);
744 if (name1->length != name2->length)
745 return (ISC_FALSE);
747 l = name1->labels;
749 if (l != name2->labels)
750 return (ISC_FALSE);
752 label1 = name1->ndata;
753 label2 = name2->ndata;
754 while (l > 0) {
755 l--;
756 count = *label1++;
757 if (count != *label2++)
758 return (ISC_FALSE);
760 INSIST(count <= 63); /* no bitstring support */
762 while (count > 0) {
763 count--;
764 c = maptolower[*label1++];
765 if (c != maptolower[*label2++])
766 return (ISC_FALSE);
770 return (ISC_TRUE);
773 isc_boolean_t
774 dns_name_caseequal(const dns_name_t *name1, const dns_name_t *name2) {
777 * Are 'name1' and 'name2' equal?
779 * Note: It makes no sense for one of the names to be relative and the
780 * other absolute. If both names are relative, then to be meaningfully
781 * compared the caller must ensure that they are both relative to the
782 * same domain.
785 REQUIRE(VALID_NAME(name1));
786 REQUIRE(VALID_NAME(name2));
788 * Either name1 is absolute and name2 is absolute, or neither is.
790 REQUIRE((name1->attributes & DNS_NAMEATTR_ABSOLUTE) ==
791 (name2->attributes & DNS_NAMEATTR_ABSOLUTE));
793 if (name1->length != name2->length)
794 return (ISC_FALSE);
796 if (memcmp(name1->ndata, name2->ndata, name1->length) != 0)
797 return (ISC_FALSE);
799 return (ISC_TRUE);
803 dns_name_rdatacompare(const dns_name_t *name1, const dns_name_t *name2) {
804 unsigned int l1, l2, l, count1, count2, count;
805 unsigned char c1, c2;
806 unsigned char *label1, *label2;
809 * Compare two absolute names as rdata.
812 REQUIRE(VALID_NAME(name1));
813 REQUIRE(name1->labels > 0);
814 REQUIRE((name1->attributes & DNS_NAMEATTR_ABSOLUTE) != 0);
815 REQUIRE(VALID_NAME(name2));
816 REQUIRE(name2->labels > 0);
817 REQUIRE((name2->attributes & DNS_NAMEATTR_ABSOLUTE) != 0);
819 l1 = name1->labels;
820 l2 = name2->labels;
822 l = (l1 < l2) ? l1 : l2;
824 label1 = name1->ndata;
825 label2 = name2->ndata;
826 while (l > 0) {
827 l--;
828 count1 = *label1++;
829 count2 = *label2++;
831 /* no bitstring support */
832 INSIST(count1 <= 63 && count2 <= 63);
834 if (count1 != count2)
835 return ((count1 < count2) ? -1 : 1);
836 count = count1;
837 while (count > 0) {
838 count--;
839 c1 = maptolower[*label1++];
840 c2 = maptolower[*label2++];
841 if (c1 < c2)
842 return (-1);
843 else if (c1 > c2)
844 return (1);
849 * If one name had more labels than the other, their common
850 * prefix must have been different because the shorter name
851 * ended with the root label and the longer one can't have
852 * a root label in the middle of it. Therefore, if we get
853 * to this point, the lengths must be equal.
855 INSIST(l1 == l2);
857 return (0);
860 isc_boolean_t
861 dns_name_issubdomain(const dns_name_t *name1, const dns_name_t *name2) {
862 int order;
863 unsigned int nlabels;
864 dns_namereln_t namereln;
867 * Is 'name1' a subdomain of 'name2'?
869 * Note: It makes no sense for one of the names to be relative and the
870 * other absolute. If both names are relative, then to be meaningfully
871 * compared the caller must ensure that they are both relative to the
872 * same domain.
875 namereln = dns_name_fullcompare(name1, name2, &order, &nlabels);
876 if (namereln == dns_namereln_subdomain ||
877 namereln == dns_namereln_equal)
878 return (ISC_TRUE);
880 return (ISC_FALSE);
883 isc_boolean_t
884 dns_name_matcheswildcard(const dns_name_t *name, const dns_name_t *wname) {
885 int order;
886 unsigned int nlabels, labels;
887 dns_name_t tname;
889 REQUIRE(VALID_NAME(name));
890 REQUIRE(name->labels > 0);
891 REQUIRE(VALID_NAME(wname));
892 labels = wname->labels;
893 REQUIRE(labels > 0);
894 REQUIRE(dns_name_iswildcard(wname));
896 #if defined(__clang__) && \
897 ( __clang_major__ < 3 || (__clang_major__ == 3 && __clang_minor__ < 2))
898 memset(&tname, 0, sizeof(tname));
899 #endif
900 DNS_NAME_INIT(&tname, NULL);
901 dns_name_getlabelsequence(wname, 1, labels - 1, &tname);
902 if (dns_name_fullcompare(name, &tname, &order, &nlabels) ==
903 dns_namereln_subdomain)
904 return (ISC_TRUE);
905 return (ISC_FALSE);
908 unsigned int
909 dns_name_countlabels(const dns_name_t *name) {
911 * How many labels does 'name' have?
914 REQUIRE(VALID_NAME(name));
916 ENSURE(name->labels <= 128);
918 return (name->labels);
921 void
922 dns_name_getlabel(const dns_name_t *name, unsigned int n, dns_label_t *label) {
923 unsigned char *offsets;
924 dns_offsets_t odata;
927 * Make 'label' refer to the 'n'th least significant label of 'name'.
930 REQUIRE(VALID_NAME(name));
931 REQUIRE(name->labels > 0);
932 REQUIRE(n < name->labels);
933 REQUIRE(label != NULL);
935 SETUP_OFFSETS(name, offsets, odata);
937 label->base = &name->ndata[offsets[n]];
938 if (n == name->labels - 1)
939 label->length = name->length - offsets[n];
940 else
941 label->length = offsets[n + 1] - offsets[n];
944 void
945 dns_name_getlabelsequence(const dns_name_t *source,
946 unsigned int first, unsigned int n,
947 dns_name_t *target)
949 unsigned char *offsets;
950 dns_offsets_t odata;
951 unsigned int firstoffset, endoffset;
954 * Make 'target' refer to the 'n' labels including and following
955 * 'first' in 'source'.
958 REQUIRE(VALID_NAME(source));
959 REQUIRE(VALID_NAME(target));
960 REQUIRE(first <= source->labels);
961 REQUIRE(n <= source->labels - first); /* note first+n could overflow */
962 REQUIRE(BINDABLE(target));
964 SETUP_OFFSETS(source, offsets, odata);
966 if (first == source->labels)
967 firstoffset = source->length;
968 else
969 firstoffset = offsets[first];
971 if (first + n == source->labels)
972 endoffset = source->length;
973 else
974 endoffset = offsets[first + n];
976 target->ndata = &source->ndata[firstoffset];
977 target->length = endoffset - firstoffset;
979 if (first + n == source->labels && n > 0 &&
980 (source->attributes & DNS_NAMEATTR_ABSOLUTE) != 0)
981 target->attributes |= DNS_NAMEATTR_ABSOLUTE;
982 else
983 target->attributes &= ~DNS_NAMEATTR_ABSOLUTE;
985 target->labels = n;
988 * If source and target are the same, and we're making target
989 * a prefix of source, the offsets table is correct already
990 * so we don't need to call set_offsets().
992 if (target->offsets != NULL &&
993 (target != source || first != 0))
994 set_offsets(target, target->offsets, NULL);
997 void
998 dns_name_clone(const dns_name_t *source, dns_name_t *target) {
1001 * Make 'target' refer to the same name as 'source'.
1004 REQUIRE(VALID_NAME(source));
1005 REQUIRE(VALID_NAME(target));
1006 REQUIRE(BINDABLE(target));
1008 target->ndata = source->ndata;
1009 target->length = source->length;
1010 target->labels = source->labels;
1011 target->attributes = source->attributes &
1012 (unsigned int)~(DNS_NAMEATTR_READONLY | DNS_NAMEATTR_DYNAMIC |
1013 DNS_NAMEATTR_DYNOFFSETS);
1014 if (target->offsets != NULL && source->labels > 0) {
1015 if (source->offsets != NULL)
1016 memmove(target->offsets, source->offsets,
1017 source->labels);
1018 else
1019 set_offsets(target, target->offsets, NULL);
1023 void
1024 dns_name_fromregion(dns_name_t *name, const isc_region_t *r) {
1025 unsigned char *offsets;
1026 dns_offsets_t odata;
1027 unsigned int len;
1028 isc_region_t r2;
1031 * Make 'name' refer to region 'r'.
1034 REQUIRE(VALID_NAME(name));
1035 REQUIRE(r != NULL);
1036 REQUIRE(BINDABLE(name));
1038 INIT_OFFSETS(name, offsets, odata);
1040 if (name->buffer != NULL) {
1041 isc_buffer_clear(name->buffer);
1042 isc_buffer_availableregion(name->buffer, &r2);
1043 len = (r->length < r2.length) ? r->length : r2.length;
1044 if (len > DNS_NAME_MAXWIRE)
1045 len = DNS_NAME_MAXWIRE;
1046 memmove(r2.base, r->base, len);
1047 name->ndata = r2.base;
1048 name->length = len;
1049 } else {
1050 name->ndata = r->base;
1051 name->length = (r->length <= DNS_NAME_MAXWIRE) ?
1052 r->length : DNS_NAME_MAXWIRE;
1055 if (r->length > 0)
1056 set_offsets(name, offsets, name);
1057 else {
1058 name->labels = 0;
1059 name->attributes &= ~DNS_NAMEATTR_ABSOLUTE;
1062 if (name->buffer != NULL)
1063 isc_buffer_add(name->buffer, name->length);
1066 void
1067 dns_name_toregion(dns_name_t *name, isc_region_t *r) {
1069 * Make 'r' refer to 'name'.
1072 REQUIRE(VALID_NAME(name));
1073 REQUIRE(r != NULL);
1075 DNS_NAME_TOREGION(name, r);
1078 isc_result_t
1079 dns_name_fromtext(dns_name_t *name, isc_buffer_t *source,
1080 const dns_name_t *origin, unsigned int options,
1081 isc_buffer_t *target)
1083 unsigned char *ndata, *label = NULL;
1084 char *tdata;
1085 char c;
1086 ft_state state;
1087 unsigned int value = 0, count = 0;
1088 unsigned int n1 = 0, n2 = 0;
1089 unsigned int tlen, nrem, nused, digits = 0, labels, tused;
1090 isc_boolean_t done;
1091 unsigned char *offsets;
1092 dns_offsets_t odata;
1093 isc_boolean_t downcase;
1096 * Convert the textual representation of a DNS name at source
1097 * into uncompressed wire form stored in target.
1099 * Notes:
1100 * Relative domain names will have 'origin' appended to them
1101 * unless 'origin' is NULL, in which case relative domain names
1102 * will remain relative.
1105 REQUIRE(VALID_NAME(name));
1106 REQUIRE(ISC_BUFFER_VALID(source));
1107 REQUIRE((target != NULL && ISC_BUFFER_VALID(target)) ||
1108 (target == NULL && ISC_BUFFER_VALID(name->buffer)));
1110 downcase = ISC_TF((options & DNS_NAME_DOWNCASE) != 0);
1112 if (target == NULL && name->buffer != NULL) {
1113 target = name->buffer;
1114 isc_buffer_clear(target);
1117 REQUIRE(BINDABLE(name));
1119 INIT_OFFSETS(name, offsets, odata);
1120 offsets[0] = 0;
1123 * Make 'name' empty in case of failure.
1125 MAKE_EMPTY(name);
1128 * Set up the state machine.
1130 tdata = (char *)source->base + source->current;
1131 tlen = isc_buffer_remaininglength(source);
1132 tused = 0;
1133 ndata = isc_buffer_used(target);
1134 nrem = isc_buffer_availablelength(target);
1135 if (nrem > 255)
1136 nrem = 255;
1137 nused = 0;
1138 labels = 0;
1139 done = ISC_FALSE;
1140 state = ft_init;
1142 while (nrem > 0 && tlen > 0 && !done) {
1143 c = *tdata++;
1144 tlen--;
1145 tused++;
1147 switch (state) {
1148 case ft_init:
1150 * Is this the root name?
1152 if (c == '.') {
1153 if (tlen != 0)
1154 return (DNS_R_EMPTYLABEL);
1155 labels++;
1156 *ndata++ = 0;
1157 nrem--;
1158 nused++;
1159 done = ISC_TRUE;
1160 break;
1162 if (c == '@' && tlen == 0) {
1163 state = ft_at;
1164 break;
1167 /* FALLTHROUGH */
1168 case ft_start:
1169 label = ndata;
1170 ndata++;
1171 nrem--;
1172 nused++;
1173 count = 0;
1174 if (c == '\\') {
1175 state = ft_initialescape;
1176 break;
1178 state = ft_ordinary;
1179 if (nrem == 0)
1180 return (ISC_R_NOSPACE);
1181 /* FALLTHROUGH */
1182 case ft_ordinary:
1183 if (c == '.') {
1184 if (count == 0)
1185 return (DNS_R_EMPTYLABEL);
1186 *label = count;
1187 labels++;
1188 INSIST(labels <= 127);
1189 offsets[labels] = nused;
1190 if (tlen == 0) {
1191 labels++;
1192 *ndata++ = 0;
1193 nrem--;
1194 nused++;
1195 done = ISC_TRUE;
1197 state = ft_start;
1198 } else if (c == '\\') {
1199 state = ft_escape;
1200 } else {
1201 if (count >= 63)
1202 return (DNS_R_LABELTOOLONG);
1203 count++;
1204 CONVERTTOASCII(c);
1205 if (downcase)
1206 c = maptolower[c & 0xff];
1207 *ndata++ = c;
1208 nrem--;
1209 nused++;
1211 break;
1212 case ft_initialescape:
1213 if (c == '[') {
1215 * This looks like a bitstring label, which
1216 * was deprecated. Intentionally drop it.
1218 return (DNS_R_BADLABELTYPE);
1220 state = ft_escape;
1221 POST(state);
1222 /* FALLTHROUGH */
1223 case ft_escape:
1224 if (!isdigit(c & 0xff)) {
1225 if (count >= 63)
1226 return (DNS_R_LABELTOOLONG);
1227 count++;
1228 CONVERTTOASCII(c);
1229 if (downcase)
1230 c = maptolower[c & 0xff];
1231 *ndata++ = c;
1232 nrem--;
1233 nused++;
1234 state = ft_ordinary;
1235 break;
1237 digits = 0;
1238 value = 0;
1239 state = ft_escdecimal;
1240 /* FALLTHROUGH */
1241 case ft_escdecimal:
1242 if (!isdigit(c & 0xff))
1243 return (DNS_R_BADESCAPE);
1244 value *= 10;
1245 value += digitvalue[c & 0xff];
1246 digits++;
1247 if (digits == 3) {
1248 if (value > 255)
1249 return (DNS_R_BADESCAPE);
1250 if (count >= 63)
1251 return (DNS_R_LABELTOOLONG);
1252 count++;
1253 if (downcase)
1254 value = maptolower[value];
1255 *ndata++ = value;
1256 nrem--;
1257 nused++;
1258 state = ft_ordinary;
1260 break;
1261 default:
1262 FATAL_ERROR(__FILE__, __LINE__,
1263 "Unexpected state %d", state);
1264 /* Does not return. */
1268 if (!done) {
1269 if (nrem == 0)
1270 return (ISC_R_NOSPACE);
1271 INSIST(tlen == 0);
1272 if (state != ft_ordinary && state != ft_at)
1273 return (ISC_R_UNEXPECTEDEND);
1274 if (state == ft_ordinary) {
1275 INSIST(count != 0);
1276 *label = count;
1277 labels++;
1278 INSIST(labels <= 127);
1279 offsets[labels] = nused;
1281 if (origin != NULL) {
1282 if (nrem < origin->length)
1283 return (ISC_R_NOSPACE);
1284 label = origin->ndata;
1285 n1 = origin->length;
1286 nrem -= n1;
1287 POST(nrem);
1288 while (n1 > 0) {
1289 n2 = *label++;
1290 INSIST(n2 <= 63); /* no bitstring support */
1291 *ndata++ = n2;
1292 n1 -= n2 + 1;
1293 nused += n2 + 1;
1294 while (n2 > 0) {
1295 c = *label++;
1296 if (downcase)
1297 c = maptolower[c & 0xff];
1298 *ndata++ = c;
1299 n2--;
1301 labels++;
1302 if (n1 > 0) {
1303 INSIST(labels <= 127);
1304 offsets[labels] = nused;
1307 if ((origin->attributes & DNS_NAMEATTR_ABSOLUTE) != 0)
1308 name->attributes |= DNS_NAMEATTR_ABSOLUTE;
1310 } else
1311 name->attributes |= DNS_NAMEATTR_ABSOLUTE;
1313 name->ndata = (unsigned char *)target->base + target->used;
1314 name->labels = labels;
1315 name->length = nused;
1317 isc_buffer_forward(source, tused);
1318 isc_buffer_add(target, name->length);
1320 return (ISC_R_SUCCESS);
1323 #ifdef ISC_PLATFORM_USETHREADS
1324 static void
1325 free_specific(void *arg) {
1326 dns_name_totextfilter_t *mem = arg;
1327 isc_mem_put(thread_key_mctx, mem, sizeof(*mem));
1328 /* Stop use being called again. */
1329 (void)isc_thread_key_setspecific(totext_filter_proc_key, NULL);
1332 static void
1333 thread_key_mutex_init(void) {
1334 RUNTIME_CHECK(isc_mutex_init(&thread_key_mutex) == ISC_R_SUCCESS);
1337 static isc_result_t
1338 totext_filter_proc_key_init(void) {
1339 isc_result_t result;
1342 * We need the call to isc_once_do() to support profiled mutex
1343 * otherwise thread_key_mutex could be initialized at compile time.
1345 result = isc_once_do(&once, thread_key_mutex_init);
1346 if (result != ISC_R_SUCCESS)
1347 return (result);
1349 if (!thread_key_initialized) {
1350 LOCK(&thread_key_mutex);
1351 if (thread_key_mctx == NULL)
1352 result = isc_mem_create2(0, 0, &thread_key_mctx, 0);
1353 if (result != ISC_R_SUCCESS)
1354 goto unlock;
1355 isc_mem_setname(thread_key_mctx, "threadkey", NULL);
1356 isc_mem_setdestroycheck(thread_key_mctx, ISC_FALSE);
1358 if (!thread_key_initialized &&
1359 isc_thread_key_create(&totext_filter_proc_key,
1360 free_specific) != 0) {
1361 result = ISC_R_FAILURE;
1362 isc_mem_detach(&thread_key_mctx);
1363 } else
1364 thread_key_initialized = 1;
1365 unlock:
1366 UNLOCK(&thread_key_mutex);
1368 return (result);
1370 #endif
1372 isc_result_t
1373 dns_name_totext(dns_name_t *name, isc_boolean_t omit_final_dot,
1374 isc_buffer_t *target)
1376 unsigned int options = DNS_NAME_MASTERFILE;
1378 if (omit_final_dot)
1379 options |= DNS_NAME_OMITFINALDOT;
1380 return (dns_name_totext2(name, options, target));
1383 isc_result_t
1384 dns_name_toprincipal(dns_name_t *name, isc_buffer_t *target) {
1385 return (dns_name_totext2(name, DNS_NAME_OMITFINALDOT, target));
1388 isc_result_t
1389 dns_name_totext2(dns_name_t *name, unsigned int options, isc_buffer_t *target)
1391 unsigned char *ndata;
1392 char *tdata;
1393 unsigned int nlen, tlen;
1394 unsigned char c;
1395 unsigned int trem, count;
1396 unsigned int labels;
1397 isc_boolean_t saw_root = ISC_FALSE;
1398 unsigned int oused = target->used;
1399 #ifdef ISC_PLATFORM_USETHREADS
1400 dns_name_totextfilter_t *mem;
1401 dns_name_totextfilter_t totext_filter_proc = NULL;
1402 isc_result_t result;
1403 #endif
1404 isc_boolean_t omit_final_dot =
1405 ISC_TF(options & DNS_NAME_OMITFINALDOT);
1408 * This function assumes the name is in proper uncompressed
1409 * wire format.
1411 REQUIRE(VALID_NAME(name));
1412 REQUIRE(ISC_BUFFER_VALID(target));
1414 #ifdef ISC_PLATFORM_USETHREADS
1415 result = totext_filter_proc_key_init();
1416 if (result != ISC_R_SUCCESS)
1417 return (result);
1418 #endif
1419 ndata = name->ndata;
1420 nlen = name->length;
1421 labels = name->labels;
1422 tdata = isc_buffer_used(target);
1423 tlen = isc_buffer_availablelength(target);
1425 trem = tlen;
1427 if (labels == 0 && nlen == 0) {
1429 * Special handling for an empty name.
1431 if (trem == 0)
1432 return (ISC_R_NOSPACE);
1435 * The names of these booleans are misleading in this case.
1436 * This empty name is not necessarily from the root node of
1437 * the DNS root zone, nor is a final dot going to be included.
1438 * They need to be set this way, though, to keep the "@"
1439 * from being trounced.
1441 saw_root = ISC_TRUE;
1442 omit_final_dot = ISC_FALSE;
1443 *tdata++ = '@';
1444 trem--;
1447 * Skip the while() loop.
1449 nlen = 0;
1450 } else if (nlen == 1 && labels == 1 && *ndata == '\0') {
1452 * Special handling for the root label.
1454 if (trem == 0)
1455 return (ISC_R_NOSPACE);
1457 saw_root = ISC_TRUE;
1458 omit_final_dot = ISC_FALSE;
1459 *tdata++ = '.';
1460 trem--;
1463 * Skip the while() loop.
1465 nlen = 0;
1468 while (labels > 0 && nlen > 0 && trem > 0) {
1469 labels--;
1470 count = *ndata++;
1471 nlen--;
1472 if (count == 0) {
1473 saw_root = ISC_TRUE;
1474 break;
1476 if (count < 64) {
1477 INSIST(nlen >= count);
1478 while (count > 0) {
1479 c = *ndata;
1480 switch (c) {
1481 /* Special modifiers in zone files. */
1482 case 0x40: /* '@' */
1483 case 0x24: /* '$' */
1484 if ((options & DNS_NAME_MASTERFILE) == 0)
1485 goto no_escape;
1486 /* FALLTHROUGH */
1487 case 0x22: /* '"' */
1488 case 0x28: /* '(' */
1489 case 0x29: /* ')' */
1490 case 0x2E: /* '.' */
1491 case 0x3B: /* ';' */
1492 case 0x5C: /* '\\' */
1493 if (trem < 2)
1494 return (ISC_R_NOSPACE);
1495 *tdata++ = '\\';
1496 CONVERTFROMASCII(c);
1497 *tdata++ = c;
1498 ndata++;
1499 trem -= 2;
1500 nlen--;
1501 break;
1502 no_escape:
1503 default:
1504 if (c > 0x20 && c < 0x7f) {
1505 if (trem == 0)
1506 return (ISC_R_NOSPACE);
1507 CONVERTFROMASCII(c);
1508 *tdata++ = c;
1509 ndata++;
1510 trem--;
1511 nlen--;
1512 } else {
1513 if (trem < 4)
1514 return (ISC_R_NOSPACE);
1515 *tdata++ = 0x5c;
1516 *tdata++ = 0x30 +
1517 ((c / 100) % 10);
1518 *tdata++ = 0x30 +
1519 ((c / 10) % 10);
1520 *tdata++ = 0x30 + (c % 10);
1521 trem -= 4;
1522 ndata++;
1523 nlen--;
1526 count--;
1528 } else {
1529 FATAL_ERROR(__FILE__, __LINE__,
1530 "Unexpected label type %02x", count);
1531 /* NOTREACHED */
1535 * The following assumes names are absolute. If not, we
1536 * fix things up later. Note that this means that in some
1537 * cases one more byte of text buffer is required than is
1538 * needed in the final output.
1540 if (trem == 0)
1541 return (ISC_R_NOSPACE);
1542 *tdata++ = '.';
1543 trem--;
1546 if (nlen != 0 && trem == 0)
1547 return (ISC_R_NOSPACE);
1549 if (!saw_root || omit_final_dot)
1550 trem++;
1552 isc_buffer_add(target, tlen - trem);
1554 #ifdef ISC_PLATFORM_USETHREADS
1555 mem = isc_thread_key_getspecific(totext_filter_proc_key);
1556 if (mem != NULL)
1557 totext_filter_proc = *mem;
1558 #endif
1559 if (totext_filter_proc != NULL)
1560 return ((*totext_filter_proc)(target, oused, saw_root));
1562 return (ISC_R_SUCCESS);
1565 isc_result_t
1566 dns_name_tofilenametext(dns_name_t *name, isc_boolean_t omit_final_dot,
1567 isc_buffer_t *target)
1569 unsigned char *ndata;
1570 char *tdata;
1571 unsigned int nlen, tlen;
1572 unsigned char c;
1573 unsigned int trem, count;
1574 unsigned int labels;
1577 * This function assumes the name is in proper uncompressed
1578 * wire format.
1580 REQUIRE(VALID_NAME(name));
1581 REQUIRE((name->attributes & DNS_NAMEATTR_ABSOLUTE) != 0);
1582 REQUIRE(ISC_BUFFER_VALID(target));
1584 ndata = name->ndata;
1585 nlen = name->length;
1586 labels = name->labels;
1587 tdata = isc_buffer_used(target);
1588 tlen = isc_buffer_availablelength(target);
1590 trem = tlen;
1592 if (nlen == 1 && labels == 1 && *ndata == '\0') {
1594 * Special handling for the root label.
1596 if (trem == 0)
1597 return (ISC_R_NOSPACE);
1599 omit_final_dot = ISC_FALSE;
1600 *tdata++ = '.';
1601 trem--;
1604 * Skip the while() loop.
1606 nlen = 0;
1609 while (labels > 0 && nlen > 0 && trem > 0) {
1610 labels--;
1611 count = *ndata++;
1612 nlen--;
1613 if (count == 0)
1614 break;
1615 if (count < 64) {
1616 INSIST(nlen >= count);
1617 while (count > 0) {
1618 c = *ndata;
1619 if ((c >= 0x30 && c <= 0x39) || /* digit */
1620 (c >= 0x41 && c <= 0x5A) || /* uppercase */
1621 (c >= 0x61 && c <= 0x7A) || /* lowercase */
1622 c == 0x2D || /* hyphen */
1623 c == 0x5F) /* underscore */
1625 if (trem == 0)
1626 return (ISC_R_NOSPACE);
1627 /* downcase */
1628 if (c >= 0x41 && c <= 0x5A)
1629 c += 0x20;
1630 CONVERTFROMASCII(c);
1631 *tdata++ = c;
1632 ndata++;
1633 trem--;
1634 nlen--;
1635 } else {
1636 if (trem < 3)
1637 return (ISC_R_NOSPACE);
1638 sprintf(tdata, "%%%02X", c);
1639 tdata += 3;
1640 trem -= 3;
1641 ndata++;
1642 nlen--;
1644 count--;
1646 } else {
1647 FATAL_ERROR(__FILE__, __LINE__,
1648 "Unexpected label type %02x", count);
1649 /* NOTREACHED */
1653 * The following assumes names are absolute. If not, we
1654 * fix things up later. Note that this means that in some
1655 * cases one more byte of text buffer is required than is
1656 * needed in the final output.
1658 if (trem == 0)
1659 return (ISC_R_NOSPACE);
1660 *tdata++ = '.';
1661 trem--;
1664 if (nlen != 0 && trem == 0)
1665 return (ISC_R_NOSPACE);
1667 if (omit_final_dot)
1668 trem++;
1670 isc_buffer_add(target, tlen - trem);
1672 return (ISC_R_SUCCESS);
1675 isc_result_t
1676 dns_name_downcase(dns_name_t *source, dns_name_t *name, isc_buffer_t *target) {
1677 unsigned char *sndata, *ndata;
1678 unsigned int nlen, count, labels;
1679 isc_buffer_t buffer;
1682 * Downcase 'source'.
1685 REQUIRE(VALID_NAME(source));
1686 REQUIRE(VALID_NAME(name));
1687 if (source == name) {
1688 REQUIRE((name->attributes & DNS_NAMEATTR_READONLY) == 0);
1689 isc_buffer_init(&buffer, source->ndata, source->length);
1690 target = &buffer;
1691 ndata = source->ndata;
1692 } else {
1693 REQUIRE(BINDABLE(name));
1694 REQUIRE((target != NULL && ISC_BUFFER_VALID(target)) ||
1695 (target == NULL && ISC_BUFFER_VALID(name->buffer)));
1696 if (target == NULL) {
1697 target = name->buffer;
1698 isc_buffer_clear(name->buffer);
1700 ndata = (unsigned char *)target->base + target->used;
1701 name->ndata = ndata;
1704 sndata = source->ndata;
1705 nlen = source->length;
1706 labels = source->labels;
1708 if (nlen > (target->length - target->used)) {
1709 MAKE_EMPTY(name);
1710 return (ISC_R_NOSPACE);
1713 while (labels > 0 && nlen > 0) {
1714 labels--;
1715 count = *sndata++;
1716 *ndata++ = count;
1717 nlen--;
1718 if (count < 64) {
1719 INSIST(nlen >= count);
1720 while (count > 0) {
1721 *ndata++ = maptolower[(*sndata++)];
1722 nlen--;
1723 count--;
1725 } else {
1726 FATAL_ERROR(__FILE__, __LINE__,
1727 "Unexpected label type %02x", count);
1728 /* Does not return. */
1732 if (source != name) {
1733 name->labels = source->labels;
1734 name->length = source->length;
1735 if ((source->attributes & DNS_NAMEATTR_ABSOLUTE) != 0)
1736 name->attributes = DNS_NAMEATTR_ABSOLUTE;
1737 else
1738 name->attributes = 0;
1739 if (name->labels > 0 && name->offsets != NULL)
1740 set_offsets(name, name->offsets, NULL);
1743 isc_buffer_add(target, name->length);
1745 return (ISC_R_SUCCESS);
1748 static void
1749 set_offsets(const dns_name_t *name, unsigned char *offsets,
1750 dns_name_t *set_name)
1752 unsigned int offset, count, length, nlabels;
1753 unsigned char *ndata;
1754 isc_boolean_t absolute;
1756 ndata = name->ndata;
1757 length = name->length;
1758 offset = 0;
1759 nlabels = 0;
1760 absolute = ISC_FALSE;
1761 while (offset != length) {
1762 INSIST(nlabels < 128);
1763 offsets[nlabels++] = offset;
1764 count = *ndata++;
1765 offset++;
1766 INSIST(count <= 63);
1767 offset += count;
1768 ndata += count;
1769 INSIST(offset <= length);
1770 if (count == 0) {
1771 absolute = ISC_TRUE;
1772 break;
1775 if (set_name != NULL) {
1776 INSIST(set_name == name);
1778 set_name->labels = nlabels;
1779 set_name->length = offset;
1780 if (absolute)
1781 set_name->attributes |= DNS_NAMEATTR_ABSOLUTE;
1782 else
1783 set_name->attributes &= ~DNS_NAMEATTR_ABSOLUTE;
1785 INSIST(nlabels == name->labels);
1786 INSIST(offset == name->length);
1789 isc_result_t
1790 dns_name_fromwire(dns_name_t *name, isc_buffer_t *source,
1791 dns_decompress_t *dctx, unsigned int options,
1792 isc_buffer_t *target)
1794 unsigned char *cdata, *ndata;
1795 unsigned int cused; /* Bytes of compressed name data used */
1796 unsigned int nused, labels, n, nmax;
1797 unsigned int current, new_current, biggest_pointer;
1798 isc_boolean_t done;
1799 fw_state state = fw_start;
1800 unsigned int c;
1801 unsigned char *offsets;
1802 dns_offsets_t odata;
1803 isc_boolean_t downcase;
1804 isc_boolean_t seen_pointer;
1807 * Copy the possibly-compressed name at source into target,
1808 * decompressing it. Loop prevention is performed by checking
1809 * the new pointer against biggest_pointer.
1812 REQUIRE(VALID_NAME(name));
1813 REQUIRE((target != NULL && ISC_BUFFER_VALID(target)) ||
1814 (target == NULL && ISC_BUFFER_VALID(name->buffer)));
1816 downcase = ISC_TF((options & DNS_NAME_DOWNCASE) != 0);
1818 if (target == NULL && name->buffer != NULL) {
1819 target = name->buffer;
1820 isc_buffer_clear(target);
1823 REQUIRE(dctx != NULL);
1824 REQUIRE(BINDABLE(name));
1826 INIT_OFFSETS(name, offsets, odata);
1829 * Make 'name' empty in case of failure.
1831 MAKE_EMPTY(name);
1834 * Initialize things to make the compiler happy; they're not required.
1836 n = 0;
1837 new_current = 0;
1840 * Set up.
1842 labels = 0;
1843 done = ISC_FALSE;
1845 ndata = isc_buffer_used(target);
1846 nused = 0;
1847 seen_pointer = ISC_FALSE;
1850 * Find the maximum number of uncompressed target name
1851 * bytes we are willing to generate. This is the smaller
1852 * of the available target buffer length and the
1853 * maximum legal domain name length (255).
1855 nmax = isc_buffer_availablelength(target);
1856 if (nmax > DNS_NAME_MAXWIRE)
1857 nmax = DNS_NAME_MAXWIRE;
1859 cdata = isc_buffer_current(source);
1860 cused = 0;
1862 current = source->current;
1863 biggest_pointer = current;
1866 * Note: The following code is not optimized for speed, but
1867 * rather for correctness. Speed will be addressed in the future.
1870 while (current < source->active && !done) {
1871 c = *cdata++;
1872 current++;
1873 if (!seen_pointer)
1874 cused++;
1876 switch (state) {
1877 case fw_start:
1878 if (c < 64) {
1879 offsets[labels] = nused;
1880 labels++;
1881 if (nused + c + 1 > nmax)
1882 goto full;
1883 nused += c + 1;
1884 *ndata++ = c;
1885 if (c == 0)
1886 done = ISC_TRUE;
1887 n = c;
1888 state = fw_ordinary;
1889 } else if (c >= 128 && c < 192) {
1891 * 14 bit local compression pointer.
1892 * Local compression is no longer an
1893 * IETF draft.
1895 return (DNS_R_BADLABELTYPE);
1896 } else if (c >= 192) {
1898 * Ordinary 14-bit pointer.
1900 if ((dctx->allowed & DNS_COMPRESS_GLOBAL14) ==
1902 return (DNS_R_DISALLOWED);
1903 new_current = c & 0x3F;
1904 state = fw_newcurrent;
1905 } else
1906 return (DNS_R_BADLABELTYPE);
1907 break;
1908 case fw_ordinary:
1909 if (downcase)
1910 c = maptolower[c];
1911 *ndata++ = c;
1912 n--;
1913 if (n == 0)
1914 state = fw_start;
1915 break;
1916 case fw_newcurrent:
1917 new_current *= 256;
1918 new_current += c;
1919 if (new_current >= biggest_pointer)
1920 return (DNS_R_BADPOINTER);
1921 biggest_pointer = new_current;
1922 current = new_current;
1923 cdata = (unsigned char *)source->base + current;
1924 seen_pointer = ISC_TRUE;
1925 state = fw_start;
1926 break;
1927 default:
1928 FATAL_ERROR(__FILE__, __LINE__,
1929 "Unknown state %d", state);
1930 /* Does not return. */
1934 if (!done)
1935 return (ISC_R_UNEXPECTEDEND);
1937 name->ndata = (unsigned char *)target->base + target->used;
1938 name->labels = labels;
1939 name->length = nused;
1940 name->attributes |= DNS_NAMEATTR_ABSOLUTE;
1942 isc_buffer_forward(source, cused);
1943 isc_buffer_add(target, name->length);
1945 return (ISC_R_SUCCESS);
1947 full:
1948 if (nmax == DNS_NAME_MAXWIRE)
1950 * The name did not fit even though we had a buffer
1951 * big enough to fit a maximum-length name.
1953 return (DNS_R_NAMETOOLONG);
1954 else
1956 * The name might fit if only the caller could give us a
1957 * big enough buffer.
1959 return (ISC_R_NOSPACE);
1962 isc_result_t
1963 dns_name_towire(const dns_name_t *name, dns_compress_t *cctx,
1964 isc_buffer_t *target)
1966 unsigned int methods;
1967 isc_uint16_t offset;
1968 dns_name_t gp; /* Global compression prefix */
1969 isc_boolean_t gf; /* Global compression target found */
1970 isc_uint16_t go; /* Global compression offset */
1971 dns_offsets_t clo;
1972 dns_name_t clname;
1975 * Convert 'name' into wire format, compressing it as specified by the
1976 * compression context 'cctx', and storing the result in 'target'.
1979 REQUIRE(VALID_NAME(name));
1980 REQUIRE(cctx != NULL);
1981 REQUIRE(ISC_BUFFER_VALID(target));
1984 * If 'name' doesn't have an offsets table, make a clone which
1985 * has one.
1987 if (name->offsets == NULL) {
1988 #if defined(__clang__) && \
1989 ( __clang_major__ < 3 || (__clang_major__ == 3 && __clang_minor__ < 2))
1990 memset(&clname, 0, sizeof(clname));
1991 #endif
1992 DNS_NAME_INIT(&clname, clo);
1993 dns_name_clone(name, &clname);
1994 name = &clname;
1996 DNS_NAME_INIT(&gp, NULL);
1998 offset = target->used; /*XXX*/
2000 methods = dns_compress_getmethods(cctx);
2002 if ((name->attributes & DNS_NAMEATTR_NOCOMPRESS) == 0 &&
2003 (methods & DNS_COMPRESS_GLOBAL14) != 0)
2004 gf = dns_compress_findglobal(cctx, name, &gp, &go);
2005 else
2006 gf = ISC_FALSE;
2009 * If the offset is too high for 14 bit global compression, we're
2010 * out of luck.
2012 if (gf && go >= 0x4000)
2013 gf = ISC_FALSE;
2016 * Will the compression pointer reduce the message size?
2018 if (gf && (gp.length + 2) >= name->length)
2019 gf = ISC_FALSE;
2021 if (gf) {
2022 if (target->length - target->used < gp.length)
2023 return (ISC_R_NOSPACE);
2024 (void)memmove((unsigned char *)target->base + target->used,
2025 gp.ndata, (size_t)gp.length);
2026 isc_buffer_add(target, gp.length);
2027 go |= 0xc000;
2028 if (target->length - target->used < 2)
2029 return (ISC_R_NOSPACE);
2030 isc_buffer_putuint16(target, go);
2031 if (gp.length != 0)
2032 dns_compress_add(cctx, name, &gp, offset);
2033 } else {
2034 if (target->length - target->used < name->length)
2035 return (ISC_R_NOSPACE);
2036 (void)memmove((unsigned char *)target->base + target->used,
2037 name->ndata, (size_t)name->length);
2038 isc_buffer_add(target, name->length);
2039 dns_compress_add(cctx, name, name, offset);
2041 return (ISC_R_SUCCESS);
2044 isc_result_t
2045 dns_name_concatenate(dns_name_t *prefix, dns_name_t *suffix, dns_name_t *name,
2046 isc_buffer_t *target)
2048 unsigned char *ndata, *offsets;
2049 unsigned int nrem, labels, prefix_length, length;
2050 isc_boolean_t copy_prefix = ISC_TRUE;
2051 isc_boolean_t copy_suffix = ISC_TRUE;
2052 isc_boolean_t absolute = ISC_FALSE;
2053 dns_name_t tmp_name;
2054 dns_offsets_t odata;
2057 * Concatenate 'prefix' and 'suffix'.
2060 REQUIRE(prefix == NULL || VALID_NAME(prefix));
2061 REQUIRE(suffix == NULL || VALID_NAME(suffix));
2062 REQUIRE(name == NULL || VALID_NAME(name));
2063 REQUIRE((target != NULL && ISC_BUFFER_VALID(target)) ||
2064 (target == NULL && name != NULL && ISC_BUFFER_VALID(name->buffer)));
2065 if (prefix == NULL || prefix->labels == 0)
2066 copy_prefix = ISC_FALSE;
2067 if (suffix == NULL || suffix->labels == 0)
2068 copy_suffix = ISC_FALSE;
2069 if (copy_prefix &&
2070 (prefix->attributes & DNS_NAMEATTR_ABSOLUTE) != 0) {
2071 absolute = ISC_TRUE;
2072 REQUIRE(!copy_suffix);
2074 if (name == NULL) {
2075 DNS_NAME_INIT(&tmp_name, odata);
2076 name = &tmp_name;
2078 if (target == NULL) {
2079 INSIST(name->buffer != NULL);
2080 target = name->buffer;
2081 isc_buffer_clear(name->buffer);
2084 REQUIRE(BINDABLE(name));
2087 * Set up.
2089 nrem = target->length - target->used;
2090 ndata = (unsigned char *)target->base + target->used;
2091 if (nrem > DNS_NAME_MAXWIRE)
2092 nrem = DNS_NAME_MAXWIRE;
2093 length = 0;
2094 prefix_length = 0;
2095 labels = 0;
2096 if (copy_prefix) {
2097 prefix_length = prefix->length;
2098 length += prefix_length;
2099 labels += prefix->labels;
2101 if (copy_suffix) {
2102 length += suffix->length;
2103 labels += suffix->labels;
2105 if (length > DNS_NAME_MAXWIRE) {
2106 MAKE_EMPTY(name);
2107 return (DNS_R_NAMETOOLONG);
2109 if (length > nrem) {
2110 MAKE_EMPTY(name);
2111 return (ISC_R_NOSPACE);
2114 if (copy_suffix) {
2115 if ((suffix->attributes & DNS_NAMEATTR_ABSOLUTE) != 0)
2116 absolute = ISC_TRUE;
2117 memmove(ndata + prefix_length, suffix->ndata, suffix->length);
2121 * If 'prefix' and 'name' are the same object, and the object has
2122 * a dedicated buffer, and we're using it, then we don't have to
2123 * copy anything.
2125 if (copy_prefix && (prefix != name || prefix->buffer != target))
2126 memmove(ndata, prefix->ndata, prefix_length);
2128 name->ndata = ndata;
2129 name->labels = labels;
2130 name->length = length;
2131 if (absolute)
2132 name->attributes = DNS_NAMEATTR_ABSOLUTE;
2133 else
2134 name->attributes = 0;
2136 if (name->labels > 0 && name->offsets != NULL) {
2137 INIT_OFFSETS(name, offsets, odata);
2138 set_offsets(name, offsets, NULL);
2141 isc_buffer_add(target, name->length);
2143 return (ISC_R_SUCCESS);
2146 void
2147 dns_name_split(dns_name_t *name, unsigned int suffixlabels,
2148 dns_name_t *prefix, dns_name_t *suffix)
2151 unsigned int splitlabel;
2153 REQUIRE(VALID_NAME(name));
2154 REQUIRE(suffixlabels > 0);
2155 REQUIRE(suffixlabels < name->labels);
2156 REQUIRE(prefix != NULL || suffix != NULL);
2157 REQUIRE(prefix == NULL ||
2158 (VALID_NAME(prefix) &&
2159 prefix->buffer != NULL &&
2160 BINDABLE(prefix)));
2161 REQUIRE(suffix == NULL ||
2162 (VALID_NAME(suffix) &&
2163 suffix->buffer != NULL &&
2164 BINDABLE(suffix)));
2166 splitlabel = name->labels - suffixlabels;
2168 if (prefix != NULL)
2169 dns_name_getlabelsequence(name, 0, splitlabel, prefix);
2171 if (suffix != NULL)
2172 dns_name_getlabelsequence(name, splitlabel,
2173 suffixlabels, suffix);
2175 return;
2178 isc_result_t
2179 dns_name_dup(const dns_name_t *source, isc_mem_t *mctx,
2180 dns_name_t *target)
2183 * Make 'target' a dynamically allocated copy of 'source'.
2186 REQUIRE(VALID_NAME(source));
2187 REQUIRE(source->length > 0);
2188 REQUIRE(VALID_NAME(target));
2189 REQUIRE(BINDABLE(target));
2192 * Make 'target' empty in case of failure.
2194 MAKE_EMPTY(target);
2196 target->ndata = isc_mem_get(mctx, source->length);
2197 if (target->ndata == NULL)
2198 return (ISC_R_NOMEMORY);
2200 memmove(target->ndata, source->ndata, source->length);
2202 target->length = source->length;
2203 target->labels = source->labels;
2204 target->attributes = DNS_NAMEATTR_DYNAMIC;
2205 if ((source->attributes & DNS_NAMEATTR_ABSOLUTE) != 0)
2206 target->attributes |= DNS_NAMEATTR_ABSOLUTE;
2207 if (target->offsets != NULL) {
2208 if (source->offsets != NULL)
2209 memmove(target->offsets, source->offsets,
2210 source->labels);
2211 else
2212 set_offsets(target, target->offsets, NULL);
2215 return (ISC_R_SUCCESS);
2218 isc_result_t
2219 dns_name_dupwithoffsets(dns_name_t *source, isc_mem_t *mctx,
2220 dns_name_t *target)
2223 * Make 'target' a read-only dynamically allocated copy of 'source'.
2224 * 'target' will also have a dynamically allocated offsets table.
2227 REQUIRE(VALID_NAME(source));
2228 REQUIRE(source->length > 0);
2229 REQUIRE(VALID_NAME(target));
2230 REQUIRE(BINDABLE(target));
2231 REQUIRE(target->offsets == NULL);
2234 * Make 'target' empty in case of failure.
2236 MAKE_EMPTY(target);
2238 target->ndata = isc_mem_get(mctx, source->length + source->labels);
2239 if (target->ndata == NULL)
2240 return (ISC_R_NOMEMORY);
2242 memmove(target->ndata, source->ndata, source->length);
2244 target->length = source->length;
2245 target->labels = source->labels;
2246 target->attributes = DNS_NAMEATTR_DYNAMIC | DNS_NAMEATTR_DYNOFFSETS |
2247 DNS_NAMEATTR_READONLY;
2248 if ((source->attributes & DNS_NAMEATTR_ABSOLUTE) != 0)
2249 target->attributes |= DNS_NAMEATTR_ABSOLUTE;
2250 target->offsets = target->ndata + source->length;
2251 if (source->offsets != NULL)
2252 memmove(target->offsets, source->offsets, source->labels);
2253 else
2254 set_offsets(target, target->offsets, NULL);
2256 return (ISC_R_SUCCESS);
2259 void
2260 dns_name_free(dns_name_t *name, isc_mem_t *mctx) {
2261 size_t size;
2264 * Free 'name'.
2267 REQUIRE(VALID_NAME(name));
2268 REQUIRE((name->attributes & DNS_NAMEATTR_DYNAMIC) != 0);
2270 size = name->length;
2271 if ((name->attributes & DNS_NAMEATTR_DYNOFFSETS) != 0)
2272 size += name->labels;
2273 isc_mem_put(mctx, name->ndata, size);
2274 dns_name_invalidate(name);
2277 isc_result_t
2278 dns_name_digest(dns_name_t *name, dns_digestfunc_t digest, void *arg) {
2279 dns_name_t downname;
2280 unsigned char data[256];
2281 isc_buffer_t buffer;
2282 isc_result_t result;
2283 isc_region_t r;
2286 * Send 'name' in DNSSEC canonical form to 'digest'.
2289 REQUIRE(VALID_NAME(name));
2290 REQUIRE(digest != NULL);
2292 #if defined(__clang__) && \
2293 ( __clang_major__ < 3 || (__clang_major__ == 3 && __clang_minor__ < 2))
2294 memset(&downname, 0, sizeof(downname));
2295 #endif
2296 DNS_NAME_INIT(&downname, NULL);
2298 isc_buffer_init(&buffer, data, sizeof(data));
2300 result = dns_name_downcase(name, &downname, &buffer);
2301 if (result != ISC_R_SUCCESS)
2302 return (result);
2304 isc_buffer_usedregion(&buffer, &r);
2306 return ((digest)(arg, &r));
2309 isc_boolean_t
2310 dns_name_dynamic(dns_name_t *name) {
2311 REQUIRE(VALID_NAME(name));
2314 * Returns whether there is dynamic memory associated with this name.
2317 return ((name->attributes & DNS_NAMEATTR_DYNAMIC) != 0 ?
2318 ISC_TRUE : ISC_FALSE);
2321 isc_result_t
2322 dns_name_print(dns_name_t *name, FILE *stream) {
2323 isc_result_t result;
2324 isc_buffer_t b;
2325 isc_region_t r;
2326 char t[1024];
2329 * Print 'name' on 'stream'.
2332 REQUIRE(VALID_NAME(name));
2334 isc_buffer_init(&b, t, sizeof(t));
2335 result = dns_name_totext(name, ISC_FALSE, &b);
2336 if (result != ISC_R_SUCCESS)
2337 return (result);
2338 isc_buffer_usedregion(&b, &r);
2339 fprintf(stream, "%.*s", (int)r.length, (char *)r.base);
2341 return (ISC_R_SUCCESS);
2344 isc_result_t
2345 dns_name_settotextfilter(dns_name_totextfilter_t proc) {
2346 #ifdef ISC_PLATFORM_USETHREADS
2347 isc_result_t result;
2348 dns_name_totextfilter_t *mem;
2349 int res;
2351 result = totext_filter_proc_key_init();
2352 if (result != ISC_R_SUCCESS)
2353 return (result);
2356 * If we already have been here set / clear as appropriate.
2357 * Otherwise allocate memory.
2359 mem = isc_thread_key_getspecific(totext_filter_proc_key);
2360 if (mem != NULL && proc != NULL) {
2361 *mem = proc;
2362 return (ISC_R_SUCCESS);
2364 if (proc == NULL) {
2365 isc_mem_put(thread_key_mctx, mem, sizeof(*mem));
2366 res = isc_thread_key_setspecific(totext_filter_proc_key, NULL);
2367 if (res != 0)
2368 result = ISC_R_UNEXPECTED;
2369 return (result);
2372 mem = isc_mem_get(thread_key_mctx, sizeof(*mem));
2373 if (mem == NULL)
2374 return (ISC_R_NOMEMORY);
2375 *mem = proc;
2376 if (isc_thread_key_setspecific(totext_filter_proc_key, mem) != 0) {
2377 isc_mem_put(thread_key_mctx, mem, sizeof(*mem));
2378 result = ISC_R_UNEXPECTED;
2380 return (result);
2381 #else
2382 totext_filter_proc = proc;
2383 return (ISC_R_SUCCESS);
2384 #endif
2387 void
2388 dns_name_format(dns_name_t *name, char *cp, unsigned int size) {
2389 isc_result_t result;
2390 isc_buffer_t buf;
2392 REQUIRE(size > 0);
2395 * Leave room for null termination after buffer.
2397 isc_buffer_init(&buf, cp, size - 1);
2398 result = dns_name_totext(name, ISC_TRUE, &buf);
2399 if (result == ISC_R_SUCCESS) {
2401 * Null terminate.
2403 isc_region_t r;
2404 isc_buffer_usedregion(&buf, &r);
2405 ((char *) r.base)[r.length] = '\0';
2407 } else
2408 snprintf(cp, size, "<unknown>");
2412 * dns_name_tostring() -- similar to dns_name_format() but allocates its own
2413 * memory.
2415 isc_result_t
2416 dns_name_tostring(dns_name_t *name, char **target, isc_mem_t *mctx) {
2417 isc_result_t result;
2418 isc_buffer_t buf;
2419 isc_region_t reg;
2420 char *p, txt[DNS_NAME_FORMATSIZE];
2422 REQUIRE(VALID_NAME(name));
2423 REQUIRE(target != NULL && *target == NULL);
2425 isc_buffer_init(&buf, txt, sizeof(txt));
2426 result = dns_name_totext(name, ISC_FALSE, &buf);
2427 if (result != ISC_R_SUCCESS)
2428 return (result);
2430 isc_buffer_usedregion(&buf, &reg);
2431 p = isc_mem_allocate(mctx, reg.length + 1);
2432 memmove(p, (char *) reg.base, (int) reg.length);
2433 p[reg.length] = '\0';
2435 *target = p;
2436 return (ISC_R_SUCCESS);
2440 * dns_name_fromstring() -- convert directly from a string to a name,
2441 * allocating memory as needed
2443 isc_result_t
2444 dns_name_fromstring(dns_name_t *target, const char *src, unsigned int options,
2445 isc_mem_t *mctx)
2447 return (dns_name_fromstring2(target, src, dns_rootname, options, mctx));
2450 isc_result_t
2451 dns_name_fromstring2(dns_name_t *target, const char *src,
2452 const dns_name_t *origin, unsigned int options,
2453 isc_mem_t *mctx)
2455 isc_result_t result;
2456 isc_buffer_t buf;
2457 dns_fixedname_t fn;
2458 dns_name_t *name;
2460 REQUIRE(src != NULL);
2462 isc_buffer_constinit(&buf, src, strlen(src));
2463 isc_buffer_add(&buf, strlen(src));
2464 if (BINDABLE(target) && target->buffer != NULL)
2465 name = target;
2466 else {
2467 dns_fixedname_init(&fn);
2468 name = dns_fixedname_name(&fn);
2471 result = dns_name_fromtext(name, &buf, origin, options, NULL);
2472 if (result != ISC_R_SUCCESS)
2473 return (result);
2475 if (name != target)
2476 result = dns_name_dupwithoffsets(name, mctx, target);
2477 return (result);
2480 isc_result_t
2481 dns_name_copy(dns_name_t *source, dns_name_t *dest, isc_buffer_t *target) {
2482 unsigned char *ndata;
2485 * Make dest a copy of source.
2488 REQUIRE(VALID_NAME(source));
2489 REQUIRE(VALID_NAME(dest));
2490 REQUIRE(target != NULL || dest->buffer != NULL);
2492 if (target == NULL) {
2493 target = dest->buffer;
2494 isc_buffer_clear(dest->buffer);
2497 REQUIRE(BINDABLE(dest));
2500 * Set up.
2502 if (target->length - target->used < source->length)
2503 return (ISC_R_NOSPACE);
2505 ndata = (unsigned char *)target->base + target->used;
2506 dest->ndata = target->base;
2508 memmove(ndata, source->ndata, source->length);
2510 dest->ndata = ndata;
2511 dest->labels = source->labels;
2512 dest->length = source->length;
2513 if ((source->attributes & DNS_NAMEATTR_ABSOLUTE) != 0)
2514 dest->attributes = DNS_NAMEATTR_ABSOLUTE;
2515 else
2516 dest->attributes = 0;
2518 if (dest->labels > 0 && dest->offsets != NULL) {
2519 if (source->offsets != NULL)
2520 memmove(dest->offsets, source->offsets, source->labels);
2521 else
2522 set_offsets(dest, dest->offsets, NULL);
2525 isc_buffer_add(target, dest->length);
2527 return (ISC_R_SUCCESS);
2530 void
2531 dns_name_destroy(void) {
2532 #ifdef ISC_PLATFORM_USETHREADS
2533 RUNTIME_CHECK(isc_once_do(&once, thread_key_mutex_init)
2534 == ISC_R_SUCCESS);
2536 LOCK(&thread_key_mutex);
2537 if (thread_key_initialized) {
2538 isc_mem_detach(&thread_key_mctx);
2539 isc_thread_key_delete(totext_filter_proc_key);
2540 thread_key_initialized = 0;
2542 UNLOCK(&thread_key_mutex);
2544 #endif