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