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