1 /* 2 * dname.c -- Domain name handling. 3 * 4 * Copyright (c) 2001-2006, NLnet Labs. All rights reserved. 5 * 6 * See LICENSE for the license. 7 * 8 */ 9 10 11 #include "config.h" 12 13 #include <sys/types.h> 14 15 #include <assert.h> 16 #include <ctype.h> 17 #include <limits.h> 18 #include <stdio.h> 19 #include <string.h> 20 21 #include "dns.h" 22 #include "dname.h" 23 #include "query.h" 24 25 const dname_type * 26 dname_make(region_type *region, const uint8_t *name, int normalize) 27 { 28 size_t name_size = 0; 29 uint8_t label_offsets[MAXDOMAINLEN]; 30 uint8_t label_count = 0; 31 const uint8_t *label = name; 32 dname_type *result; 33 ssize_t i; 34 35 assert(name); 36 37 while (1) { 38 if (label_is_pointer(label)) 39 return NULL; 40 41 label_offsets[label_count] = (uint8_t) (label - name); 42 ++label_count; 43 name_size += label_length(label) + 1; 44 45 if (label_is_root(label)) 46 break; 47 48 label = label_next(label); 49 } 50 51 if (name_size > MAXDOMAINLEN) 52 return NULL; 53 54 assert(label_count <= MAXDOMAINLEN / 2 + 1); 55 56 /* Reverse label offsets. */ 57 for (i = 0; i < label_count / 2; ++i) { 58 uint8_t tmp = label_offsets[i]; 59 label_offsets[i] = label_offsets[label_count - i - 1]; 60 label_offsets[label_count - i - 1] = tmp; 61 } 62 63 result = (dname_type *) region_alloc( 64 region, 65 (sizeof(dname_type) 66 + (((size_t)label_count) + ((size_t)name_size)) * sizeof(uint8_t))); 67 result->name_size = name_size; 68 result->label_count = label_count; 69 memcpy((uint8_t *) dname_label_offsets(result), 70 label_offsets, 71 label_count * sizeof(uint8_t)); 72 if (normalize) { 73 uint8_t *dst = (uint8_t *) dname_name(result); 74 const uint8_t *src = name; 75 while (!label_is_root(src)) { 76 ssize_t len = label_length(src); 77 *dst++ = *src++; 78 for (i = 0; i < len; ++i) { 79 *dst++ = DNAME_NORMALIZE((unsigned char)*src++); 80 } 81 } 82 *dst = *src; 83 } else { 84 memcpy((uint8_t *) dname_name(result), 85 name, 86 name_size * sizeof(uint8_t)); 87 } 88 return result; 89 } 90 91 92 const dname_type * 93 dname_make_from_packet(region_type *region, buffer_type *packet, 94 int allow_pointers, int normalize) 95 { 96 uint8_t buf[MAXDOMAINLEN + 1]; 97 if(!dname_make_wire_from_packet(buf, packet, allow_pointers)) 98 return 0; 99 return dname_make(region, buf, normalize); 100 } 101 102 int 103 dname_make_wire_from_packet(uint8_t *buf, buffer_type *packet, 104 int allow_pointers) 105 { 106 int done = 0; 107 uint8_t visited[(MAX_PACKET_SIZE+7)/8]; 108 size_t dname_length = 0; 109 const uint8_t *label; 110 ssize_t mark = -1; 111 112 if(sizeof(visited)<(buffer_limit(packet)+7)/8) 113 memset(visited, 0, sizeof(visited)); 114 else memset(visited, 0, (buffer_limit(packet)+7)/8); 115 116 while (!done) { 117 if (!buffer_available(packet, 1)) { 118 /* error("dname out of bounds"); */ 119 return 0; 120 } 121 122 if (get_bit(visited, buffer_position(packet))) { 123 /* error("dname loops"); */ 124 return 0; 125 } 126 set_bit(visited, buffer_position(packet)); 127 128 label = buffer_current(packet); 129 if (label_is_pointer(label)) { 130 size_t pointer; 131 if (!allow_pointers) { 132 return 0; 133 } 134 if (!buffer_available(packet, 2)) { 135 /* error("dname pointer out of bounds"); */ 136 return 0; 137 } 138 pointer = label_pointer_location(label); 139 if (pointer >= buffer_limit(packet)) { 140 /* error("dname pointer points outside packet"); */ 141 return 0; 142 } 143 buffer_skip(packet, 2); 144 if (mark == -1) { 145 mark = buffer_position(packet); 146 } 147 buffer_set_position(packet, pointer); 148 } else if (label_is_normal(label)) { 149 size_t length = label_length(label) + 1; 150 done = label_is_root(label); 151 if (!buffer_available(packet, length)) { 152 /* error("dname label out of bounds"); */ 153 return 0; 154 } 155 if (dname_length + length >= MAXDOMAINLEN+1) { 156 /* error("dname too large"); */ 157 return 0; 158 } 159 buffer_read(packet, buf + dname_length, length); 160 dname_length += length; 161 } else { 162 /* error("bad label type"); */ 163 return 0; 164 } 165 } 166 167 if (mark != -1) { 168 buffer_set_position(packet, mark); 169 } 170 171 return dname_length; 172 } 173 174 const dname_type * 175 dname_parse(region_type *region, const char *name) 176 { 177 uint8_t dname[MAXDOMAINLEN]; 178 if(!dname_parse_wire(dname, name)) 179 return 0; 180 return dname_make(region, dname, 1); 181 } 182 183 int dname_parse_wire(uint8_t* dname, const char* name) 184 { 185 const uint8_t *s = (const uint8_t *) name; 186 uint8_t *h; 187 uint8_t *p; 188 uint8_t *d = dname; 189 size_t label_length; 190 191 if (strcmp(name, ".") == 0) { 192 /* Root domain. */ 193 dname[0] = 0; 194 return 1; 195 } 196 197 for (h = d, p = h + 1; *s; ++s, ++p) { 198 if (p - dname >= MAXDOMAINLEN) { 199 return 0; 200 } 201 202 switch (*s) { 203 case '.': 204 if (p == h + 1) { 205 /* Empty label. */ 206 return 0; 207 } else { 208 label_length = p - h - 1; 209 if (label_length > MAXLABELLEN) { 210 return 0; 211 } 212 *h = label_length; 213 h = p; 214 } 215 break; 216 case '\\': 217 /* Handle escaped characters (RFC1035 5.1) */ 218 if (isdigit((unsigned char)s[1]) && isdigit((unsigned char)s[2]) && isdigit((unsigned char)s[3])) { 219 int val = (hexdigit_to_int(s[1]) * 100 + 220 hexdigit_to_int(s[2]) * 10 + 221 hexdigit_to_int(s[3])); 222 if (0 <= val && val <= 255) { 223 s += 3; 224 *p = val; 225 } else { 226 *p = *++s; 227 } 228 } else if (s[1] != '\0') { 229 *p = *++s; 230 } 231 break; 232 default: 233 *p = *s; 234 break; 235 } 236 } 237 238 if (p != h + 1) { 239 /* Terminate last label. */ 240 label_length = p - h - 1; 241 if (label_length > MAXLABELLEN) { 242 return 0; 243 } 244 *h = label_length; 245 h = p; 246 p++; 247 } 248 249 /* Add root label. */ 250 if (h - dname >= MAXDOMAINLEN) { 251 return 0; 252 } 253 *h = 0; 254 255 return p-dname; 256 } 257 258 259 const dname_type * 260 dname_copy(region_type *region, const dname_type *dname) 261 { 262 return (dname_type *) region_alloc_init( 263 region, dname, dname_total_size(dname)); 264 } 265 266 267 const dname_type * 268 dname_partial_copy(region_type *region, const dname_type *dname, uint8_t label_count) 269 { 270 if (!dname) 271 return NULL; 272 273 if (label_count == 0) { 274 /* Always copy the root label. */ 275 label_count = 1; 276 } 277 278 assert(label_count <= dname->label_count); 279 280 return dname_make(region, dname_label(dname, label_count - 1), 0); 281 } 282 283 284 const dname_type * 285 dname_origin(region_type *region, const dname_type *dname) 286 { 287 return dname_partial_copy(region, dname, dname->label_count - 1); 288 } 289 290 291 int 292 dname_is_subdomain(const dname_type *left, const dname_type *right) 293 { 294 uint8_t i; 295 296 if (left->label_count < right->label_count) 297 return 0; 298 299 for (i = 1; i < right->label_count; ++i) { 300 if (label_compare(dname_label(left, i), 301 dname_label(right, i)) != 0) 302 return 0; 303 } 304 305 return 1; 306 } 307 308 309 int 310 dname_compare(const dname_type *left, const dname_type *right) 311 { 312 int result; 313 uint8_t label_count; 314 uint8_t i; 315 316 assert(left); 317 assert(right); 318 319 if (left == right) { 320 return 0; 321 } 322 323 label_count = (left->label_count <= right->label_count 324 ? left->label_count 325 : right->label_count); 326 327 /* Skip the root label by starting at label 1. */ 328 for (i = 1; i < label_count; ++i) { 329 result = label_compare(dname_label(left, i), 330 dname_label(right, i)); 331 if (result) { 332 return result; 333 } 334 } 335 336 /* Dname with the fewest labels is "first". */ 337 /* the subtraction works because the size of int is much larger than 338 * the label count and the values won't wrap around */ 339 return (int) left->label_count - (int) right->label_count; 340 } 341 342 343 int 344 label_compare(const uint8_t *left, const uint8_t *right) 345 { 346 int left_length; 347 int right_length; 348 size_t size; 349 int result; 350 351 assert(left); 352 assert(right); 353 354 assert(label_is_normal(left)); 355 assert(label_is_normal(right)); 356 357 left_length = label_length(left); 358 right_length = label_length(right); 359 size = left_length < right_length ? left_length : right_length; 360 361 result = memcmp(label_data(left), label_data(right), size); 362 if (result) { 363 return result; 364 } else { 365 /* the subtraction works because the size of int is much 366 * larger than the lengths and the values won't wrap around */ 367 return (int) left_length - (int) right_length; 368 } 369 } 370 371 372 uint8_t 373 dname_label_match_count(const dname_type *left, const dname_type *right) 374 { 375 uint8_t i; 376 377 assert(left); 378 assert(right); 379 380 for (i = 1; i < left->label_count && i < right->label_count; ++i) { 381 if (label_compare(dname_label(left, i), 382 dname_label(right, i)) != 0) 383 { 384 return i; 385 } 386 } 387 388 return i; 389 } 390 391 const char * 392 dname_to_string(const dname_type *dname, const dname_type *origin) 393 { 394 static char buf[MAXDOMAINLEN * 5]; 395 return dname_to_string_buf(dname, origin, buf); 396 } 397 398 const char * 399 dname_to_string_buf(const dname_type *dname, const dname_type *origin, char buf[MAXDOMAINLEN * 5]) 400 { 401 size_t i; 402 size_t labels_to_convert = dname->label_count - 1; 403 int absolute = 1; 404 char *dst; 405 const uint8_t *src; 406 407 if (dname->label_count == 1) { 408 strlcpy(buf, ".", MAXDOMAINLEN * 5); 409 return buf; 410 } 411 412 if (origin && dname_is_subdomain(dname, origin)) { 413 int common_labels = dname_label_match_count(dname, origin); 414 labels_to_convert = dname->label_count - common_labels; 415 absolute = 0; 416 } 417 418 dst = buf; 419 src = dname_name(dname); 420 for (i = 0; i < labels_to_convert; ++i) { 421 size_t len = label_length(src); 422 size_t j; 423 ++src; 424 for (j = 0; j < len; ++j) { 425 uint8_t ch = *src++; 426 if (isalnum((unsigned char)ch) || ch == '-' || ch == '_' || ch == '*') { 427 *dst++ = ch; 428 } else if (ch == '.' || ch == '\\') { 429 *dst++ = '\\'; 430 *dst++ = ch; 431 } else { 432 snprintf(dst, 5, "\\%03u", (unsigned int)ch); 433 dst += 4; 434 } 435 } 436 *dst++ = '.'; 437 } 438 if (absolute) { 439 *dst = '\0'; 440 } else { 441 *--dst = '\0'; 442 } 443 return buf; 444 } 445 446 447 const dname_type * 448 dname_make_from_label(region_type *region, 449 const uint8_t *label, const size_t length) 450 { 451 uint8_t temp[MAXLABELLEN + 2]; 452 453 assert(length > 0 && length <= MAXLABELLEN); 454 455 temp[0] = length; 456 memcpy(temp + 1, label, length * sizeof(uint8_t)); 457 temp[length + 1] = '\000'; 458 459 return dname_make(region, temp, 1); 460 } 461 462 463 const dname_type * 464 dname_concatenate(region_type *region, 465 const dname_type *left, 466 const dname_type *right) 467 { 468 uint8_t temp[MAXDOMAINLEN]; 469 470 assert(left->name_size + right->name_size - 1 <= MAXDOMAINLEN); 471 472 memcpy(temp, dname_name(left), left->name_size - 1); 473 memcpy(temp + left->name_size - 1, dname_name(right), right->name_size); 474 475 return dname_make(region, temp, 0); 476 } 477 478 479 const dname_type * 480 dname_replace(region_type* region, 481 const dname_type* name, 482 const dname_type* src, 483 const dname_type* dest) 484 { 485 /* nomenclature: name is said to be <x>.<src>. x can be null. */ 486 dname_type* res; 487 int x_labels = name->label_count - src->label_count; 488 int x_len = name->name_size - src->name_size; 489 int i; 490 assert(dname_is_subdomain(name, src)); 491 492 /* check if final size is acceptable */ 493 if(x_len+dest->name_size > MAXDOMAINLEN) 494 return NULL; 495 496 res = (dname_type*)region_alloc(region, sizeof(dname_type) + 497 (x_labels+((int)dest->label_count) + x_len+((int)dest->name_size)) 498 *sizeof(uint8_t)); 499 res->name_size = x_len+dest->name_size; 500 res->label_count = x_labels+dest->label_count; 501 for(i=0; i<dest->label_count; i++) 502 ((uint8_t*)dname_label_offsets(res))[i] = 503 dname_label_offsets(dest)[i] + x_len; 504 for(i=dest->label_count; i<res->label_count; i++) 505 ((uint8_t*)dname_label_offsets(res))[i] = 506 dname_label_offsets(name)[i - dest->label_count + 507 src->label_count]; 508 memcpy((uint8_t*)dname_name(res), dname_name(name), x_len); 509 memcpy((uint8_t*)dname_name(res)+x_len, dname_name(dest), dest->name_size); 510 assert(dname_is_subdomain(res, dest)); 511 return res; 512 } 513 514 char* wirelabel2str(const uint8_t* label) 515 { 516 static char buf[MAXDOMAINLEN*5+3]; 517 char* p = buf; 518 uint8_t lablen; 519 lablen = *label++; 520 while(lablen--) { 521 uint8_t ch = *label++; 522 if (isalnum((unsigned char)ch) || ch == '-' || ch == '_' || ch == '*') { 523 *p++ = ch; 524 } else if (ch == '.' || ch == '\\') { 525 *p++ = '\\'; 526 *p++ = ch; 527 } else { 528 snprintf(p, 5, "\\%03u", (unsigned int)ch); 529 p += 4; 530 } 531 } 532 *p++ = 0; 533 return buf; 534 } 535 536 char* wiredname2str(const uint8_t* dname) 537 { 538 static char buf[MAXDOMAINLEN*5+3]; 539 char* p = buf; 540 uint8_t lablen; 541 if(*dname == 0) { 542 strlcpy(buf, ".", sizeof(buf)); 543 return buf; 544 } 545 lablen = *dname++; 546 while(lablen) { 547 while(lablen--) { 548 uint8_t ch = *dname++; 549 if (isalnum((unsigned char)ch) || ch == '-' || ch == '_' || ch == '*') { 550 *p++ = ch; 551 } else if (ch == '.' || ch == '\\') { 552 *p++ = '\\'; 553 *p++ = ch; 554 } else { 555 snprintf(p, 5, "\\%03u", (unsigned int)ch); 556 p += 4; 557 } 558 } 559 lablen = *dname++; 560 *p++ = '.'; 561 } 562 *p++ = 0; 563 return buf; 564 } 565 566 int dname_equal_nocase(uint8_t* a, uint8_t* b, uint16_t len) 567 { 568 uint8_t i, lablen; 569 while(len > 0) { 570 /* check labellen */ 571 if(*a != *b) 572 return 0; 573 lablen = *a++; 574 b++; 575 len--; 576 /* malformed or compression ptr; we stop scanning */ 577 if((lablen & 0xc0) || len < lablen) 578 return (memcmp(a, b, len) == 0); 579 /* check the label, lowercased */ 580 for(i=0; i<lablen; i++) { 581 if(DNAME_NORMALIZE((unsigned char)*a++) != DNAME_NORMALIZE((unsigned char)*b++)) 582 return 0; 583 } 584 len -= lablen; 585 } 586 return 1; 587 } 588