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 } 247 248 /* Add root label. */ 249 if (h - dname >= MAXDOMAINLEN) { 250 return 0; 251 } 252 *h = 0; 253 254 return p-dname; 255 } 256 257 258 const dname_type * 259 dname_copy(region_type *region, const dname_type *dname) 260 { 261 return (dname_type *) region_alloc_init( 262 region, dname, dname_total_size(dname)); 263 } 264 265 266 const dname_type * 267 dname_partial_copy(region_type *region, const dname_type *dname, uint8_t label_count) 268 { 269 if (!dname) 270 return NULL; 271 272 if (label_count == 0) { 273 /* Always copy the root label. */ 274 label_count = 1; 275 } 276 277 assert(label_count <= dname->label_count); 278 279 return dname_make(region, dname_label(dname, label_count - 1), 0); 280 } 281 282 283 const dname_type * 284 dname_origin(region_type *region, const dname_type *dname) 285 { 286 return dname_partial_copy(region, dname, dname->label_count - 1); 287 } 288 289 290 int 291 dname_is_subdomain(const dname_type *left, const dname_type *right) 292 { 293 uint8_t i; 294 295 if (left->label_count < right->label_count) 296 return 0; 297 298 for (i = 1; i < right->label_count; ++i) { 299 if (label_compare(dname_label(left, i), 300 dname_label(right, i)) != 0) 301 return 0; 302 } 303 304 return 1; 305 } 306 307 308 int 309 dname_compare(const dname_type *left, const dname_type *right) 310 { 311 int result; 312 uint8_t label_count; 313 uint8_t i; 314 315 assert(left); 316 assert(right); 317 318 if (left == right) { 319 return 0; 320 } 321 322 label_count = (left->label_count <= right->label_count 323 ? left->label_count 324 : right->label_count); 325 326 /* Skip the root label by starting at label 1. */ 327 for (i = 1; i < label_count; ++i) { 328 result = label_compare(dname_label(left, i), 329 dname_label(right, i)); 330 if (result) { 331 return result; 332 } 333 } 334 335 /* Dname with the fewest labels is "first". */ 336 /* the subtraction works because the size of int is much larger than 337 * the label count and the values won't wrap around */ 338 return (int) left->label_count - (int) right->label_count; 339 } 340 341 342 int 343 label_compare(const uint8_t *left, const uint8_t *right) 344 { 345 int left_length; 346 int right_length; 347 size_t size; 348 int result; 349 350 assert(left); 351 assert(right); 352 353 assert(label_is_normal(left)); 354 assert(label_is_normal(right)); 355 356 left_length = label_length(left); 357 right_length = label_length(right); 358 size = left_length < right_length ? left_length : right_length; 359 360 result = memcmp(label_data(left), label_data(right), size); 361 if (result) { 362 return result; 363 } else { 364 /* the subtraction works because the size of int is much 365 * larger than the lengths and the values won't wrap around */ 366 return (int) left_length - (int) right_length; 367 } 368 } 369 370 371 uint8_t 372 dname_label_match_count(const dname_type *left, const dname_type *right) 373 { 374 uint8_t i; 375 376 assert(left); 377 assert(right); 378 379 for (i = 1; i < left->label_count && i < right->label_count; ++i) { 380 if (label_compare(dname_label(left, i), 381 dname_label(right, i)) != 0) 382 { 383 return i; 384 } 385 } 386 387 return i; 388 } 389 390 const char * 391 dname_to_string(const dname_type *dname, const dname_type *origin) 392 { 393 static char buf[MAXDOMAINLEN * 5]; 394 size_t i; 395 size_t labels_to_convert = dname->label_count - 1; 396 int absolute = 1; 397 char *dst; 398 const uint8_t *src; 399 400 if (dname->label_count == 1) { 401 strlcpy(buf, ".", sizeof(buf)); 402 return buf; 403 } 404 405 if (origin && dname_is_subdomain(dname, origin)) { 406 int common_labels = dname_label_match_count(dname, origin); 407 labels_to_convert = dname->label_count - common_labels; 408 absolute = 0; 409 } 410 411 dst = buf; 412 src = dname_name(dname); 413 for (i = 0; i < labels_to_convert; ++i) { 414 size_t len = label_length(src); 415 size_t j; 416 ++src; 417 for (j = 0; j < len; ++j) { 418 uint8_t ch = *src++; 419 if (isalnum((unsigned char)ch) || ch == '-' || ch == '_' || ch == '*') { 420 *dst++ = ch; 421 } else if (ch == '.' || ch == '\\') { 422 *dst++ = '\\'; 423 *dst++ = ch; 424 } else { 425 snprintf(dst, 5, "\\%03u", (unsigned int)ch); 426 dst += 4; 427 } 428 } 429 *dst++ = '.'; 430 } 431 if (absolute) { 432 *dst = '\0'; 433 } else { 434 *--dst = '\0'; 435 } 436 return buf; 437 } 438 439 440 const dname_type * 441 dname_make_from_label(region_type *region, 442 const uint8_t *label, const size_t length) 443 { 444 uint8_t temp[MAXLABELLEN + 2]; 445 446 assert(length > 0 && length <= MAXLABELLEN); 447 448 temp[0] = length; 449 memcpy(temp + 1, label, length * sizeof(uint8_t)); 450 temp[length + 1] = '\000'; 451 452 return dname_make(region, temp, 1); 453 } 454 455 456 const dname_type * 457 dname_concatenate(region_type *region, 458 const dname_type *left, 459 const dname_type *right) 460 { 461 uint8_t temp[MAXDOMAINLEN]; 462 463 assert(left->name_size + right->name_size - 1 <= MAXDOMAINLEN); 464 465 memcpy(temp, dname_name(left), left->name_size - 1); 466 memcpy(temp + left->name_size - 1, dname_name(right), right->name_size); 467 468 return dname_make(region, temp, 0); 469 } 470 471 472 const dname_type * 473 dname_replace(region_type* region, 474 const dname_type* name, 475 const dname_type* src, 476 const dname_type* dest) 477 { 478 /* nomenclature: name is said to be <x>.<src>. x can be null. */ 479 dname_type* res; 480 int x_labels = name->label_count - src->label_count; 481 int x_len = name->name_size - src->name_size; 482 int i; 483 assert(dname_is_subdomain(name, src)); 484 485 /* check if final size is acceptable */ 486 if(x_len+dest->name_size > MAXDOMAINLEN) 487 return NULL; 488 489 res = (dname_type*)region_alloc(region, sizeof(dname_type) + 490 (x_labels+((int)dest->label_count) + x_len+((int)dest->name_size)) 491 *sizeof(uint8_t)); 492 res->name_size = x_len+dest->name_size; 493 res->label_count = x_labels+dest->label_count; 494 for(i=0; i<dest->label_count; i++) 495 ((uint8_t*)dname_label_offsets(res))[i] = 496 dname_label_offsets(dest)[i] + x_len; 497 for(i=dest->label_count; i<res->label_count; i++) 498 ((uint8_t*)dname_label_offsets(res))[i] = 499 dname_label_offsets(name)[i - dest->label_count + 500 src->label_count]; 501 memcpy((uint8_t*)dname_name(res), dname_name(name), x_len); 502 memcpy((uint8_t*)dname_name(res)+x_len, dname_name(dest), dest->name_size); 503 assert(dname_is_subdomain(res, dest)); 504 return res; 505 } 506 507 char* wirelabel2str(const uint8_t* label) 508 { 509 static char buf[MAXDOMAINLEN*5+3]; 510 char* p = buf; 511 uint8_t lablen; 512 lablen = *label++; 513 while(lablen--) { 514 uint8_t ch = *label++; 515 if (isalnum((unsigned char)ch) || ch == '-' || ch == '_' || ch == '*') { 516 *p++ = ch; 517 } else if (ch == '.' || ch == '\\') { 518 *p++ = '\\'; 519 *p++ = ch; 520 } else { 521 snprintf(p, 5, "\\%03u", (unsigned int)ch); 522 p += 4; 523 } 524 } 525 *p++ = 0; 526 return buf; 527 } 528 529 char* wiredname2str(const uint8_t* dname) 530 { 531 static char buf[MAXDOMAINLEN*5+3]; 532 char* p = buf; 533 uint8_t lablen; 534 if(*dname == 0) { 535 strlcpy(buf, ".", sizeof(buf)); 536 return buf; 537 } 538 lablen = *dname++; 539 while(lablen) { 540 while(lablen--) { 541 uint8_t ch = *dname++; 542 if (isalnum((unsigned char)ch) || ch == '-' || ch == '_' || ch == '*') { 543 *p++ = ch; 544 } else if (ch == '.' || ch == '\\') { 545 *p++ = '\\'; 546 *p++ = ch; 547 } else { 548 snprintf(p, 5, "\\%03u", (unsigned int)ch); 549 p += 4; 550 } 551 } 552 lablen = *dname++; 553 *p++ = '.'; 554 } 555 *p++ = 0; 556 return buf; 557 } 558 559 int dname_equal_nocase(uint8_t* a, uint8_t* b, uint16_t len) 560 { 561 uint8_t i, lablen; 562 while(len > 0) { 563 /* check labellen */ 564 if(*a != *b) 565 return 0; 566 lablen = *a++; 567 b++; 568 len--; 569 /* malformed or compression ptr; we stop scanning */ 570 if((lablen & 0xc0) || len < lablen) 571 return (memcmp(a, b, len) == 0); 572 /* check the label, lowercased */ 573 for(i=0; i<lablen; i++) { 574 if(DNAME_NORMALIZE((unsigned char)*a++) != DNAME_NORMALIZE((unsigned char)*b++)) 575 return 0; 576 } 577 len -= lablen; 578 } 579 return 1; 580 } 581