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