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