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 size_t i; 396 size_t labels_to_convert = dname->label_count - 1; 397 int absolute = 1; 398 char *dst; 399 const uint8_t *src; 400 401 if (dname->label_count == 1) { 402 strlcpy(buf, ".", sizeof(buf)); 403 return buf; 404 } 405 406 if (origin && dname_is_subdomain(dname, origin)) { 407 int common_labels = dname_label_match_count(dname, origin); 408 labels_to_convert = dname->label_count - common_labels; 409 absolute = 0; 410 } 411 412 dst = buf; 413 src = dname_name(dname); 414 for (i = 0; i < labels_to_convert; ++i) { 415 size_t len = label_length(src); 416 size_t j; 417 ++src; 418 for (j = 0; j < len; ++j) { 419 uint8_t ch = *src++; 420 if (isalnum((unsigned char)ch) || ch == '-' || ch == '_' || ch == '*') { 421 *dst++ = ch; 422 } else if (ch == '.' || ch == '\\') { 423 *dst++ = '\\'; 424 *dst++ = ch; 425 } else { 426 snprintf(dst, 5, "\\%03u", (unsigned int)ch); 427 dst += 4; 428 } 429 } 430 *dst++ = '.'; 431 } 432 if (absolute) { 433 *dst = '\0'; 434 } else { 435 *--dst = '\0'; 436 } 437 return buf; 438 } 439 440 441 const dname_type * 442 dname_make_from_label(region_type *region, 443 const uint8_t *label, const size_t length) 444 { 445 uint8_t temp[MAXLABELLEN + 2]; 446 447 assert(length > 0 && length <= MAXLABELLEN); 448 449 temp[0] = length; 450 memcpy(temp + 1, label, length * sizeof(uint8_t)); 451 temp[length + 1] = '\000'; 452 453 return dname_make(region, temp, 1); 454 } 455 456 457 const dname_type * 458 dname_concatenate(region_type *region, 459 const dname_type *left, 460 const dname_type *right) 461 { 462 uint8_t temp[MAXDOMAINLEN]; 463 464 assert(left->name_size + right->name_size - 1 <= MAXDOMAINLEN); 465 466 memcpy(temp, dname_name(left), left->name_size - 1); 467 memcpy(temp + left->name_size - 1, dname_name(right), right->name_size); 468 469 return dname_make(region, temp, 0); 470 } 471 472 473 const dname_type * 474 dname_replace(region_type* region, 475 const dname_type* name, 476 const dname_type* src, 477 const dname_type* dest) 478 { 479 /* nomenclature: name is said to be <x>.<src>. x can be null. */ 480 dname_type* res; 481 int x_labels = name->label_count - src->label_count; 482 int x_len = name->name_size - src->name_size; 483 int i; 484 assert(dname_is_subdomain(name, src)); 485 486 /* check if final size is acceptable */ 487 if(x_len+dest->name_size > MAXDOMAINLEN) 488 return NULL; 489 490 res = (dname_type*)region_alloc(region, sizeof(dname_type) + 491 (x_labels+((int)dest->label_count) + x_len+((int)dest->name_size)) 492 *sizeof(uint8_t)); 493 res->name_size = x_len+dest->name_size; 494 res->label_count = x_labels+dest->label_count; 495 for(i=0; i<dest->label_count; i++) 496 ((uint8_t*)dname_label_offsets(res))[i] = 497 dname_label_offsets(dest)[i] + x_len; 498 for(i=dest->label_count; i<res->label_count; i++) 499 ((uint8_t*)dname_label_offsets(res))[i] = 500 dname_label_offsets(name)[i - dest->label_count + 501 src->label_count]; 502 memcpy((uint8_t*)dname_name(res), dname_name(name), x_len); 503 memcpy((uint8_t*)dname_name(res)+x_len, dname_name(dest), dest->name_size); 504 assert(dname_is_subdomain(res, dest)); 505 return res; 506 } 507 508 char* wirelabel2str(const uint8_t* label) 509 { 510 static char buf[MAXDOMAINLEN*5+3]; 511 char* p = buf; 512 uint8_t lablen; 513 lablen = *label++; 514 while(lablen--) { 515 uint8_t ch = *label++; 516 if (isalnum((unsigned char)ch) || ch == '-' || ch == '_' || ch == '*') { 517 *p++ = ch; 518 } else if (ch == '.' || ch == '\\') { 519 *p++ = '\\'; 520 *p++ = ch; 521 } else { 522 snprintf(p, 5, "\\%03u", (unsigned int)ch); 523 p += 4; 524 } 525 } 526 *p++ = 0; 527 return buf; 528 } 529 530 char* wiredname2str(const uint8_t* dname) 531 { 532 static char buf[MAXDOMAINLEN*5+3]; 533 char* p = buf; 534 uint8_t lablen; 535 if(*dname == 0) { 536 strlcpy(buf, ".", sizeof(buf)); 537 return buf; 538 } 539 lablen = *dname++; 540 while(lablen) { 541 while(lablen--) { 542 uint8_t ch = *dname++; 543 if (isalnum((unsigned char)ch) || ch == '-' || ch == '_' || ch == '*') { 544 *p++ = ch; 545 } else if (ch == '.' || ch == '\\') { 546 *p++ = '\\'; 547 *p++ = ch; 548 } else { 549 snprintf(p, 5, "\\%03u", (unsigned int)ch); 550 p += 4; 551 } 552 } 553 lablen = *dname++; 554 *p++ = '.'; 555 } 556 *p++ = 0; 557 return buf; 558 } 559 560 int dname_equal_nocase(uint8_t* a, uint8_t* b, uint16_t len) 561 { 562 uint8_t i, lablen; 563 while(len > 0) { 564 /* check labellen */ 565 if(*a != *b) 566 return 0; 567 lablen = *a++; 568 b++; 569 len--; 570 /* malformed or compression ptr; we stop scanning */ 571 if((lablen & 0xc0) || len < lablen) 572 return (memcmp(a, b, len) == 0); 573 /* check the label, lowercased */ 574 for(i=0; i<lablen; i++) { 575 if(DNAME_NORMALIZE((unsigned char)*a++) != DNAME_NORMALIZE((unsigned char)*b++)) 576 return 0; 577 } 578 len -= lablen; 579 } 580 return 1; 581 } 582