dname.c revision 246827
1/* 2 * dname.c 3 * 4 * dname specific rdata implementations 5 * A dname is a rdf structure with type LDNS_RDF_TYPE_DNAME 6 * It is not a /real/ type! All function must therefor check 7 * for LDNS_RDF_TYPE_DNAME. 8 * 9 * a Net::DNS like library for C 10 * 11 * (c) NLnet Labs, 2004-2006 12 * 13 * See the file LICENSE for the license 14 */ 15 16#include <ldns/config.h> 17 18#include <ldns/ldns.h> 19 20#ifdef HAVE_NETINET_IN_H 21#include <netinet/in.h> 22#endif 23#ifdef HAVE_SYS_SOCKET_H 24#include <sys/socket.h> 25#endif 26#ifdef HAVE_NETDB_H 27#include <netdb.h> 28#endif 29#ifdef HAVE_ARPA_INET_H 30#include <arpa/inet.h> 31#endif 32 33ldns_rdf * 34ldns_dname_cat_clone(const ldns_rdf *rd1, const ldns_rdf *rd2) 35{ 36 ldns_rdf *new; 37 uint16_t new_size; 38 uint8_t *buf; 39 uint16_t left_size; 40 41 if (ldns_rdf_get_type(rd1) != LDNS_RDF_TYPE_DNAME || 42 ldns_rdf_get_type(rd2) != LDNS_RDF_TYPE_DNAME) { 43 return NULL; 44 } 45 46 /* remove root label if it is present at the end of the left 47 * rd, by reducing the size with 1 48 */ 49 left_size = ldns_rdf_size(rd1); 50 if (left_size > 0 &&ldns_rdf_data(rd1)[left_size - 1] == 0) { 51 left_size--; 52 } 53 54 /* we overwrite the nullbyte of rd1 */ 55 new_size = left_size + ldns_rdf_size(rd2); 56 buf = LDNS_XMALLOC(uint8_t, new_size); 57 if (!buf) { 58 return NULL; 59 } 60 61 /* put the two dname's after each other */ 62 memcpy(buf, ldns_rdf_data(rd1), left_size); 63 memcpy(buf + left_size, ldns_rdf_data(rd2), ldns_rdf_size(rd2)); 64 65 new = ldns_rdf_new_frm_data(LDNS_RDF_TYPE_DNAME, new_size, buf); 66 67 LDNS_FREE(buf); 68 return new; 69} 70 71ldns_status 72ldns_dname_cat(ldns_rdf *rd1, ldns_rdf *rd2) 73{ 74 uint16_t left_size; 75 uint16_t size; 76 uint8_t* newd; 77 78 if (ldns_rdf_get_type(rd1) != LDNS_RDF_TYPE_DNAME || 79 ldns_rdf_get_type(rd2) != LDNS_RDF_TYPE_DNAME) { 80 return LDNS_STATUS_ERR; 81 } 82 83 /* remove root label if it is present at the end of the left 84 * rd, by reducing the size with 1 85 */ 86 left_size = ldns_rdf_size(rd1); 87 if (left_size > 0 &&ldns_rdf_data(rd1)[left_size - 1] == 0) { 88 left_size--; 89 } 90 91 size = left_size + ldns_rdf_size(rd2); 92 newd = LDNS_XREALLOC(ldns_rdf_data(rd1), uint8_t, size); 93 if(!newd) { 94 return LDNS_STATUS_MEM_ERR; 95 } 96 97 ldns_rdf_set_data(rd1, newd); 98 memcpy(ldns_rdf_data(rd1) + left_size, ldns_rdf_data(rd2), 99 ldns_rdf_size(rd2)); 100 ldns_rdf_set_size(rd1, size); 101 102 return LDNS_STATUS_OK; 103} 104 105ldns_rdf * 106ldns_dname_reverse(const ldns_rdf *d) 107{ 108 ldns_rdf *new; 109 ldns_rdf *tmp; 110 ldns_rdf *d_tmp; 111 ldns_status status; 112 113 d_tmp = ldns_rdf_clone(d); 114 115 new = ldns_dname_new_frm_str("."); 116 if(!new) 117 return NULL; 118 119 while(ldns_dname_label_count(d_tmp) > 0) { 120 tmp = ldns_dname_label(d_tmp, 0); 121 status = ldns_dname_cat(tmp, new); 122 if(status != LDNS_STATUS_OK) { 123 ldns_rdf_deep_free(new); 124 ldns_rdf_deep_free(d_tmp); 125 return NULL; 126 } 127 ldns_rdf_deep_free(new); 128 new = tmp; 129 tmp = ldns_dname_left_chop(d_tmp); 130 ldns_rdf_deep_free(d_tmp); 131 d_tmp = tmp; 132 } 133 ldns_rdf_deep_free(d_tmp); 134 135 return new; 136} 137 138ldns_rdf * 139ldns_dname_clone_from(const ldns_rdf *d, uint16_t n) 140{ 141 uint8_t *data; 142 uint8_t label_size; 143 size_t data_size; 144 145 if (!d || 146 ldns_rdf_get_type(d) != LDNS_RDF_TYPE_DNAME || 147 ldns_dname_label_count(d) < n) { 148 return NULL; 149 } 150 151 data = ldns_rdf_data(d); 152 data_size = ldns_rdf_size(d); 153 while (n > 0) { 154 label_size = data[0] + 1; 155 data += label_size; 156 if (data_size < label_size) { 157 /* this label is very broken */ 158 return NULL; 159 } 160 data_size -= label_size; 161 n--; 162 } 163 164 return ldns_dname_new_frm_data(data_size, data); 165} 166 167ldns_rdf * 168ldns_dname_left_chop(const ldns_rdf *d) 169{ 170 uint8_t label_pos; 171 ldns_rdf *chop; 172 173 if (!d) { 174 return NULL; 175 } 176 177 if (ldns_rdf_get_type(d) != LDNS_RDF_TYPE_DNAME) { 178 return NULL; 179 } 180 if (ldns_dname_label_count(d) == 0) { 181 /* root label */ 182 return NULL; 183 } 184 /* 05blaat02nl00 */ 185 label_pos = ldns_rdf_data(d)[0]; 186 187 chop = ldns_dname_new_frm_data(ldns_rdf_size(d) - label_pos - 1, 188 ldns_rdf_data(d) + label_pos + 1); 189 return chop; 190} 191 192uint8_t 193ldns_dname_label_count(const ldns_rdf *r) 194{ 195 uint16_t src_pos; 196 uint16_t len; 197 uint8_t i; 198 size_t r_size; 199 200 if (!r) { 201 return 0; 202 } 203 204 i = 0; 205 src_pos = 0; 206 r_size = ldns_rdf_size(r); 207 208 if (ldns_rdf_get_type(r) != LDNS_RDF_TYPE_DNAME) { 209 return 0; 210 } else { 211 len = ldns_rdf_data(r)[src_pos]; /* start of the label */ 212 213 /* single root label */ 214 if (1 == r_size) { 215 return 0; 216 } else { 217 while ((len > 0) && src_pos < r_size) { 218 src_pos++; 219 src_pos += len; 220 len = ldns_rdf_data(r)[src_pos]; 221 i++; 222 } 223 } 224 } 225 return i; 226} 227 228ldns_rdf * 229ldns_dname_new(uint16_t s, void *d) 230{ 231 ldns_rdf *rd; 232 233 rd = LDNS_MALLOC(ldns_rdf); 234 if (!rd) { 235 return NULL; 236 } 237 ldns_rdf_set_size(rd, s); 238 ldns_rdf_set_type(rd, LDNS_RDF_TYPE_DNAME); 239 ldns_rdf_set_data(rd, d); 240 return rd; 241} 242 243ldns_rdf * 244ldns_dname_new_frm_str(const char *str) 245{ 246 return ldns_rdf_new_frm_str(LDNS_RDF_TYPE_DNAME, str); 247} 248 249ldns_rdf * 250ldns_dname_new_frm_data(uint16_t size, const void *data) 251{ 252 return ldns_rdf_new_frm_data(LDNS_RDF_TYPE_DNAME, size, data); 253} 254 255void 256ldns_dname2canonical(const ldns_rdf *rd) 257{ 258 uint8_t *rdd; 259 uint16_t i; 260 261 if (ldns_rdf_get_type(rd) != LDNS_RDF_TYPE_DNAME) { 262 return; 263 } 264 265 rdd = (uint8_t*)ldns_rdf_data(rd); 266 for (i = 0; i < ldns_rdf_size(rd); i++, rdd++) { 267 *rdd = (uint8_t)LDNS_DNAME_NORMALIZE((int)*rdd); 268 } 269} 270 271bool 272ldns_dname_is_subdomain(const ldns_rdf *sub, const ldns_rdf *parent) 273{ 274 uint8_t sub_lab; 275 uint8_t par_lab; 276 int8_t i, j; 277 ldns_rdf *tmp_sub = NULL; 278 ldns_rdf *tmp_par = NULL; 279 ldns_rdf *sub_clone; 280 ldns_rdf *parent_clone; 281 bool result = true; 282 283 if (ldns_rdf_get_type(sub) != LDNS_RDF_TYPE_DNAME || 284 ldns_rdf_get_type(parent) != LDNS_RDF_TYPE_DNAME || 285 ldns_rdf_compare(sub, parent) == 0) { 286 return false; 287 } 288 289 /* would be nicer if we do not have to clone... */ 290 sub_clone = ldns_dname_clone_from(sub, 0); 291 parent_clone = ldns_dname_clone_from(parent, 0); 292 ldns_dname2canonical(sub_clone); 293 ldns_dname2canonical(parent_clone); 294 295 sub_lab = ldns_dname_label_count(sub_clone); 296 par_lab = ldns_dname_label_count(parent_clone); 297 298 /* if sub sits above parent, it cannot be a child/sub domain */ 299 if (sub_lab < par_lab) { 300 result = false; 301 } else { 302 /* check all labels the from the parent labels, from right to left. 303 * When they /all/ match we have found a subdomain 304 */ 305 j = sub_lab - 1; /* we count from zero, thank you */ 306 for (i = par_lab -1; i >= 0; i--) { 307 tmp_sub = ldns_dname_label(sub_clone, j); 308 tmp_par = ldns_dname_label(parent_clone, i); 309 if (!tmp_sub || !tmp_par) { 310 /* deep free does null check */ 311 ldns_rdf_deep_free(tmp_sub); 312 ldns_rdf_deep_free(tmp_par); 313 result = false; 314 break; 315 } 316 317 if (ldns_rdf_compare(tmp_sub, tmp_par) != 0) { 318 /* they are not equal */ 319 ldns_rdf_deep_free(tmp_sub); 320 ldns_rdf_deep_free(tmp_par); 321 result = false; 322 break; 323 } 324 ldns_rdf_deep_free(tmp_sub); 325 ldns_rdf_deep_free(tmp_par); 326 j--; 327 } 328 } 329 ldns_rdf_deep_free(sub_clone); 330 ldns_rdf_deep_free(parent_clone); 331 return result; 332} 333 334int 335ldns_dname_compare(const ldns_rdf *dname1, const ldns_rdf *dname2) 336{ 337 size_t lc1, lc2, lc1f, lc2f; 338 size_t i; 339 int result = 0; 340 uint8_t *lp1, *lp2; 341 342 /* see RFC4034 for this algorithm */ 343 /* this algorithm assumes the names are normalized to case */ 344 345 /* only when both are not NULL we can say anything about them */ 346 if (!dname1 && !dname2) { 347 return 0; 348 } 349 if (!dname1 || !dname2) { 350 return -1; 351 } 352 /* asserts must happen later as we are looking in the 353 * dname, which could be NULL. But this case is handled 354 * above 355 */ 356 assert(ldns_rdf_get_type(dname1) == LDNS_RDF_TYPE_DNAME); 357 assert(ldns_rdf_get_type(dname2) == LDNS_RDF_TYPE_DNAME); 358 359 lc1 = ldns_dname_label_count(dname1); 360 lc2 = ldns_dname_label_count(dname2); 361 362 if (lc1 == 0 && lc2 == 0) { 363 return 0; 364 } 365 if (lc1 == 0) { 366 return -1; 367 } 368 if (lc2 == 0) { 369 return 1; 370 } 371 lc1--; 372 lc2--; 373 /* we start at the last label */ 374 while (true) { 375 /* find the label first */ 376 lc1f = lc1; 377 lp1 = ldns_rdf_data(dname1); 378 while (lc1f > 0) { 379 lp1 += *lp1 + 1; 380 lc1f--; 381 } 382 383 /* and find the other one */ 384 lc2f = lc2; 385 lp2 = ldns_rdf_data(dname2); 386 while (lc2f > 0) { 387 lp2 += *lp2 + 1; 388 lc2f--; 389 } 390 391 /* now check the label character for character. */ 392 for (i = 1; i < (size_t)(*lp1 + 1); i++) { 393 if (i > *lp2) { 394 /* apparently label 1 is larger */ 395 result = 1; 396 goto done; 397 } 398 if (LDNS_DNAME_NORMALIZE((int) *(lp1 + i)) < 399 LDNS_DNAME_NORMALIZE((int) *(lp2 + i))) { 400 result = -1; 401 goto done; 402 } else if (LDNS_DNAME_NORMALIZE((int) *(lp1 + i)) > 403 LDNS_DNAME_NORMALIZE((int) *(lp2 + i))) { 404 result = 1; 405 goto done; 406 } 407 } 408 if (*lp1 < *lp2) { 409 /* apparently label 2 is larger */ 410 result = -1; 411 goto done; 412 } 413 if (lc1 == 0 && lc2 > 0) { 414 result = -1; 415 goto done; 416 } else if (lc1 > 0 && lc2 == 0) { 417 result = 1; 418 goto done; 419 } else if (lc1 == 0 && lc2 == 0) { 420 result = 0; 421 goto done; 422 } 423 lc1--; 424 lc2--; 425 } 426 427 done: 428 return result; 429} 430 431int 432ldns_dname_is_wildcard(const ldns_rdf* dname) 433{ 434 return ( ldns_dname_label_count(dname) > 0 && 435 ldns_rdf_data(dname)[0] == 1 && 436 ldns_rdf_data(dname)[1] == '*'); 437} 438 439int 440ldns_dname_match_wildcard(const ldns_rdf *dname, const ldns_rdf *wildcard) 441{ 442 ldns_rdf *wc_chopped; 443 int result; 444 /* check whether it really is a wildcard */ 445 if (ldns_dname_is_wildcard(wildcard)) { 446 /* ok, so the dname needs to be a subdomain of the wildcard 447 * without the * 448 */ 449 wc_chopped = ldns_dname_left_chop(wildcard); 450 result = (int) ldns_dname_is_subdomain(dname, wc_chopped); 451 ldns_rdf_deep_free(wc_chopped); 452 } else { 453 result = (ldns_dname_compare(dname, wildcard) == 0); 454 } 455 return result; 456} 457 458/* nsec test: does prev <= middle < next 459 * -1 = yes 460 * 0 = error/can't tell 461 * 1 = no 462 */ 463int 464ldns_dname_interval(const ldns_rdf *prev, const ldns_rdf *middle, 465 const ldns_rdf *next) 466{ 467 int prev_check, next_check; 468 469 assert(ldns_rdf_get_type(prev) == LDNS_RDF_TYPE_DNAME); 470 assert(ldns_rdf_get_type(middle) == LDNS_RDF_TYPE_DNAME); 471 assert(ldns_rdf_get_type(next) == LDNS_RDF_TYPE_DNAME); 472 473 prev_check = ldns_dname_compare(prev, middle); 474 next_check = ldns_dname_compare(middle, next); 475 /* <= next. This cannot be the case for nsec, because then we would 476 * have gotten the nsec of next... 477 */ 478 if (next_check == 0) { 479 return 0; 480 } 481 482 /* <= */ 483 if ((prev_check == -1 || prev_check == 0) && 484 /* < */ 485 next_check == -1) { 486 return -1; 487 } else { 488 return 1; 489 } 490} 491 492 493bool 494ldns_dname_str_absolute(const char *dname_str) 495{ 496 const char* s; 497 if(dname_str && strcmp(dname_str, ".") == 0) 498 return 1; 499 if(!dname_str || strlen(dname_str) < 2) 500 return 0; 501 if(dname_str[strlen(dname_str) - 1] != '.') 502 return 0; 503 if(dname_str[strlen(dname_str) - 2] != '\\') 504 return 1; /* ends in . and no \ before it */ 505 /* so we have the case of ends in . and there is \ before it */ 506 for(s=dname_str; *s; s++) { 507 if(*s == '\\') { 508 if(s[1] && s[2] && s[3] /* check length */ 509 && isdigit(s[1]) && isdigit(s[2]) && 510 isdigit(s[3])) 511 s += 3; 512 else if(!s[1] || isdigit(s[1])) /* escape of nul,0-9 */ 513 return 0; /* parse error */ 514 else s++; /* another character escaped */ 515 } 516 else if(!*(s+1) && *s == '.') 517 return 1; /* trailing dot, unescaped */ 518 } 519 return 0; 520} 521 522ldns_rdf * 523ldns_dname_label(const ldns_rdf *rdf, uint8_t labelpos) 524{ 525 uint8_t labelcnt; 526 uint16_t src_pos; 527 uint16_t len; 528 ldns_rdf *tmpnew; 529 size_t s; 530 uint8_t *data; 531 532 if (ldns_rdf_get_type(rdf) != LDNS_RDF_TYPE_DNAME) { 533 return NULL; 534 } 535 536 labelcnt = 0; 537 src_pos = 0; 538 s = ldns_rdf_size(rdf); 539 540 len = ldns_rdf_data(rdf)[src_pos]; /* label start */ 541 while ((len > 0) && src_pos < s) { 542 if (labelcnt == labelpos) { 543 /* found our label */ 544 data = LDNS_XMALLOC(uint8_t, len + 2); 545 if (!data) { 546 return NULL; 547 } 548 memcpy(data, ldns_rdf_data(rdf) + src_pos, len + 1); 549 data[len + 2 - 1] = 0; 550 551 tmpnew = ldns_rdf_new( LDNS_RDF_TYPE_DNAME 552 , len + 2, data); 553 if (!tmpnew) { 554 LDNS_FREE(data); 555 return NULL; 556 } 557 return tmpnew; 558 } 559 src_pos++; 560 src_pos += len; 561 len = ldns_rdf_data(rdf)[src_pos]; 562 labelcnt++; 563 } 564 return NULL; 565} 566