1 /* 2 * special zone file structures and functions for better dnssec handling 3 */ 4 5 #include <ldns/config.h> 6 7 #include <ldns/ldns.h> 8 9 ldns_dnssec_rrs * 10 ldns_dnssec_rrs_new(void) 11 { 12 ldns_dnssec_rrs *new_rrs; 13 new_rrs = LDNS_MALLOC(ldns_dnssec_rrs); 14 if(!new_rrs) return NULL; 15 new_rrs->rr = NULL; 16 new_rrs->next = NULL; 17 return new_rrs; 18 } 19 20 INLINE void 21 ldns_dnssec_rrs_free_internal(ldns_dnssec_rrs *rrs, int deep) 22 { 23 ldns_dnssec_rrs *next; 24 while (rrs) { 25 next = rrs->next; 26 if (deep) { 27 ldns_rr_free(rrs->rr); 28 } 29 LDNS_FREE(rrs); 30 rrs = next; 31 } 32 } 33 34 void 35 ldns_dnssec_rrs_free(ldns_dnssec_rrs *rrs) 36 { 37 ldns_dnssec_rrs_free_internal(rrs, 0); 38 } 39 40 void 41 ldns_dnssec_rrs_deep_free(ldns_dnssec_rrs *rrs) 42 { 43 ldns_dnssec_rrs_free_internal(rrs, 1); 44 } 45 46 ldns_status 47 ldns_dnssec_rrs_add_rr(ldns_dnssec_rrs *rrs, ldns_rr *rr) 48 { 49 int cmp; 50 ldns_dnssec_rrs *new_rrs; 51 if (!rrs || !rr) { 52 return LDNS_STATUS_ERR; 53 } 54 55 /* this could be done more efficiently; name and type should already 56 be equal */ 57 cmp = ldns_rr_compare(rrs->rr, rr); 58 if (cmp < 0) { 59 if (rrs->next) { 60 return ldns_dnssec_rrs_add_rr(rrs->next, rr); 61 } else { 62 new_rrs = ldns_dnssec_rrs_new(); 63 new_rrs->rr = rr; 64 rrs->next = new_rrs; 65 } 66 } else if (cmp > 0) { 67 /* put the current old rr in the new next, put the new 68 rr in the current container */ 69 new_rrs = ldns_dnssec_rrs_new(); 70 new_rrs->rr = rrs->rr; 71 new_rrs->next = rrs->next; 72 rrs->rr = rr; 73 rrs->next = new_rrs; 74 } 75 /* Silently ignore equal rr's */ 76 return LDNS_STATUS_OK; 77 } 78 79 void 80 ldns_dnssec_rrs_print_fmt(FILE *out, const ldns_output_format *fmt, 81 ldns_dnssec_rrs *rrs) 82 { 83 if (!rrs) { 84 if ((fmt->flags & LDNS_COMMENT_LAYOUT)) 85 fprintf(out, "; <void>"); 86 } else { 87 if (rrs->rr) { 88 ldns_rr_print_fmt(out, fmt, rrs->rr); 89 } 90 if (rrs->next) { 91 ldns_dnssec_rrs_print_fmt(out, fmt, rrs->next); 92 } 93 } 94 } 95 96 void 97 ldns_dnssec_rrs_print(FILE *out, ldns_dnssec_rrs *rrs) 98 { 99 ldns_dnssec_rrs_print_fmt(out, ldns_output_format_default, rrs); 100 } 101 102 103 ldns_dnssec_rrsets * 104 ldns_dnssec_rrsets_new(void) 105 { 106 ldns_dnssec_rrsets *new_rrsets; 107 new_rrsets = LDNS_MALLOC(ldns_dnssec_rrsets); 108 if(!new_rrsets) return NULL; 109 new_rrsets->rrs = NULL; 110 new_rrsets->type = 0; 111 new_rrsets->signatures = NULL; 112 new_rrsets->next = NULL; 113 return new_rrsets; 114 } 115 116 INLINE void 117 ldns_dnssec_rrsets_free_internal(ldns_dnssec_rrsets *rrsets, int deep) 118 { 119 if (rrsets) { 120 if (rrsets->rrs) { 121 ldns_dnssec_rrs_free_internal(rrsets->rrs, deep); 122 } 123 if (rrsets->next) { 124 ldns_dnssec_rrsets_free_internal(rrsets->next, deep); 125 } 126 if (rrsets->signatures) { 127 ldns_dnssec_rrs_free_internal(rrsets->signatures, deep); 128 } 129 LDNS_FREE(rrsets); 130 } 131 } 132 133 void 134 ldns_dnssec_rrsets_free(ldns_dnssec_rrsets *rrsets) 135 { 136 ldns_dnssec_rrsets_free_internal(rrsets, 0); 137 } 138 139 void 140 ldns_dnssec_rrsets_deep_free(ldns_dnssec_rrsets *rrsets) 141 { 142 ldns_dnssec_rrsets_free_internal(rrsets, 1); 143 } 144 145 ldns_rr_type 146 ldns_dnssec_rrsets_type(ldns_dnssec_rrsets *rrsets) 147 { 148 if (rrsets) { 149 return rrsets->type; 150 } else { 151 return 0; 152 } 153 } 154 155 ldns_status 156 ldns_dnssec_rrsets_set_type(ldns_dnssec_rrsets *rrsets, 157 ldns_rr_type type) 158 { 159 if (rrsets) { 160 rrsets->type = type; 161 return LDNS_STATUS_OK; 162 } 163 return LDNS_STATUS_ERR; 164 } 165 166 static ldns_dnssec_rrsets * 167 ldns_dnssec_rrsets_new_frm_rr(ldns_rr *rr) 168 { 169 ldns_dnssec_rrsets *new_rrsets; 170 ldns_rr_type rr_type; 171 bool rrsig; 172 173 new_rrsets = ldns_dnssec_rrsets_new(); 174 rr_type = ldns_rr_get_type(rr); 175 if (rr_type == LDNS_RR_TYPE_RRSIG) { 176 rrsig = true; 177 rr_type = ldns_rdf2rr_type(ldns_rr_rrsig_typecovered(rr)); 178 } else { 179 rrsig = false; 180 } 181 if (!rrsig) { 182 new_rrsets->rrs = ldns_dnssec_rrs_new(); 183 new_rrsets->rrs->rr = rr; 184 } else { 185 new_rrsets->signatures = ldns_dnssec_rrs_new(); 186 new_rrsets->signatures->rr = rr; 187 } 188 new_rrsets->type = rr_type; 189 return new_rrsets; 190 } 191 192 ldns_status 193 ldns_dnssec_rrsets_add_rr(ldns_dnssec_rrsets *rrsets, ldns_rr *rr) 194 { 195 ldns_dnssec_rrsets *new_rrsets; 196 ldns_rr_type rr_type; 197 bool rrsig = false; 198 ldns_status result = LDNS_STATUS_OK; 199 200 if (!rrsets || !rr) { 201 return LDNS_STATUS_ERR; 202 } 203 204 rr_type = ldns_rr_get_type(rr); 205 206 if (rr_type == LDNS_RR_TYPE_RRSIG) { 207 rrsig = true; 208 rr_type = ldns_rdf2rr_type(ldns_rr_rrsig_typecovered(rr)); 209 } 210 211 if (!rrsets->rrs && rrsets->type == 0 && !rrsets->signatures) { 212 if (!rrsig) { 213 rrsets->rrs = ldns_dnssec_rrs_new(); 214 rrsets->rrs->rr = rr; 215 rrsets->type = rr_type; 216 } else { 217 rrsets->signatures = ldns_dnssec_rrs_new(); 218 rrsets->signatures->rr = rr; 219 rrsets->type = rr_type; 220 } 221 return LDNS_STATUS_OK; 222 } 223 224 if (rr_type > ldns_dnssec_rrsets_type(rrsets)) { 225 if (rrsets->next) { 226 result = ldns_dnssec_rrsets_add_rr(rrsets->next, rr); 227 } else { 228 new_rrsets = ldns_dnssec_rrsets_new_frm_rr(rr); 229 rrsets->next = new_rrsets; 230 } 231 } else if (rr_type < ldns_dnssec_rrsets_type(rrsets)) { 232 /* move the current one into the new next, 233 replace field of current with data from new rr */ 234 new_rrsets = ldns_dnssec_rrsets_new(); 235 new_rrsets->rrs = rrsets->rrs; 236 new_rrsets->type = rrsets->type; 237 new_rrsets->signatures = rrsets->signatures; 238 new_rrsets->next = rrsets->next; 239 if (!rrsig) { 240 rrsets->rrs = ldns_dnssec_rrs_new(); 241 rrsets->rrs->rr = rr; 242 rrsets->signatures = NULL; 243 } else { 244 rrsets->rrs = NULL; 245 rrsets->signatures = ldns_dnssec_rrs_new(); 246 rrsets->signatures->rr = rr; 247 } 248 rrsets->type = rr_type; 249 rrsets->next = new_rrsets; 250 } else { 251 /* equal, add to current rrsets */ 252 if (rrsig) { 253 if (rrsets->signatures) { 254 result = ldns_dnssec_rrs_add_rr(rrsets->signatures, rr); 255 } else { 256 rrsets->signatures = ldns_dnssec_rrs_new(); 257 rrsets->signatures->rr = rr; 258 } 259 } else { 260 if (rrsets->rrs) { 261 result = ldns_dnssec_rrs_add_rr(rrsets->rrs, rr); 262 } else { 263 rrsets->rrs = ldns_dnssec_rrs_new(); 264 rrsets->rrs->rr = rr; 265 } 266 } 267 } 268 269 return result; 270 } 271 272 static void 273 ldns_dnssec_rrsets_print_soa_fmt(FILE *out, const ldns_output_format *fmt, 274 ldns_dnssec_rrsets *rrsets, 275 bool follow, 276 bool show_soa) 277 { 278 if (!rrsets) { 279 if ((fmt->flags & LDNS_COMMENT_LAYOUT)) 280 fprintf(out, "; <void>\n"); 281 } else { 282 if (rrsets->rrs && 283 (show_soa || 284 ldns_rr_get_type(rrsets->rrs->rr) != LDNS_RR_TYPE_SOA 285 ) 286 ) { 287 ldns_dnssec_rrs_print_fmt(out, fmt, rrsets->rrs); 288 if (rrsets->signatures) { 289 ldns_dnssec_rrs_print_fmt(out, fmt, 290 rrsets->signatures); 291 } 292 } 293 if (follow && rrsets->next) { 294 ldns_dnssec_rrsets_print_soa_fmt(out, fmt, 295 rrsets->next, follow, show_soa); 296 } 297 } 298 } 299 300 301 void 302 ldns_dnssec_rrsets_print_fmt(FILE *out, const ldns_output_format *fmt, 303 ldns_dnssec_rrsets *rrsets, 304 bool follow) 305 { 306 ldns_dnssec_rrsets_print_soa_fmt(out, fmt, rrsets, follow, true); 307 } 308 309 void 310 ldns_dnssec_rrsets_print(FILE *out, ldns_dnssec_rrsets *rrsets, bool follow) 311 { 312 ldns_dnssec_rrsets_print_fmt(out, ldns_output_format_default, 313 rrsets, follow); 314 } 315 316 ldns_dnssec_name * 317 ldns_dnssec_name_new(void) 318 { 319 ldns_dnssec_name *new_name; 320 321 new_name = LDNS_CALLOC(ldns_dnssec_name, 1); 322 if (!new_name) { 323 return NULL; 324 } 325 /* 326 * not needed anymore because CALLOC initalizes everything to zero. 327 328 new_name->name = NULL; 329 new_name->rrsets = NULL; 330 new_name->name_alloced = false; 331 new_name->nsec = NULL; 332 new_name->nsec_signatures = NULL; 333 334 new_name->is_glue = false; 335 new_name->hashed_name = NULL; 336 337 */ 338 return new_name; 339 } 340 341 ldns_dnssec_name * 342 ldns_dnssec_name_new_frm_rr(ldns_rr *rr) 343 { 344 ldns_dnssec_name *new_name = ldns_dnssec_name_new(); 345 346 new_name->name = ldns_rr_owner(rr); 347 if(ldns_dnssec_name_add_rr(new_name, rr) != LDNS_STATUS_OK) { 348 ldns_dnssec_name_free(new_name); 349 return NULL; 350 } 351 352 return new_name; 353 } 354 355 INLINE void 356 ldns_dnssec_name_free_internal(ldns_dnssec_name *name, 357 int deep) 358 { 359 if (name) { 360 if (name->name_alloced) { 361 ldns_rdf_deep_free(name->name); 362 } 363 if (name->rrsets) { 364 ldns_dnssec_rrsets_free_internal(name->rrsets, deep); 365 } 366 if (name->nsec && deep) { 367 ldns_rr_free(name->nsec); 368 } 369 if (name->nsec_signatures) { 370 ldns_dnssec_rrs_free_internal(name->nsec_signatures, deep); 371 } 372 if (name->hashed_name) { 373 if (deep) { 374 ldns_rdf_deep_free(name->hashed_name); 375 } 376 } 377 LDNS_FREE(name); 378 } 379 } 380 381 void 382 ldns_dnssec_name_free(ldns_dnssec_name *name) 383 { 384 ldns_dnssec_name_free_internal(name, 0); 385 } 386 387 void 388 ldns_dnssec_name_deep_free(ldns_dnssec_name *name) 389 { 390 ldns_dnssec_name_free_internal(name, 1); 391 } 392 393 ldns_rdf * 394 ldns_dnssec_name_name(ldns_dnssec_name *name) 395 { 396 if (name) { 397 return name->name; 398 } 399 return NULL; 400 } 401 402 bool 403 ldns_dnssec_name_is_glue(ldns_dnssec_name *name) 404 { 405 if (name) { 406 return name->is_glue; 407 } 408 return false; 409 } 410 411 void 412 ldns_dnssec_name_set_name(ldns_dnssec_name *rrset, 413 ldns_rdf *dname) 414 { 415 if (rrset && dname) { 416 rrset->name = dname; 417 } 418 } 419 420 421 void 422 ldns_dnssec_name_set_nsec(ldns_dnssec_name *rrset, ldns_rr *nsec) 423 { 424 if (rrset && nsec) { 425 rrset->nsec = nsec; 426 } 427 } 428 429 int 430 ldns_dnssec_name_cmp(const void *a, const void *b) 431 { 432 ldns_dnssec_name *na = (ldns_dnssec_name *) a; 433 ldns_dnssec_name *nb = (ldns_dnssec_name *) b; 434 435 if (na && nb) { 436 return ldns_dname_compare(ldns_dnssec_name_name(na), 437 ldns_dnssec_name_name(nb)); 438 } else if (na) { 439 return 1; 440 } else if (nb) { 441 return -1; 442 } else { 443 return 0; 444 } 445 } 446 447 ldns_status 448 ldns_dnssec_name_add_rr(ldns_dnssec_name *name, 449 ldns_rr *rr) 450 { 451 ldns_status result = LDNS_STATUS_OK; 452 ldns_rr_type rr_type; 453 ldns_rr_type typecovered = 0; 454 455 /* special handling for NSEC3 and NSECX covering RRSIGS */ 456 457 if (!name || !rr) { 458 return LDNS_STATUS_ERR; 459 } 460 461 rr_type = ldns_rr_get_type(rr); 462 463 if (rr_type == LDNS_RR_TYPE_RRSIG) { 464 typecovered = ldns_rdf2rr_type(ldns_rr_rrsig_typecovered(rr)); 465 } 466 467 if (rr_type == LDNS_RR_TYPE_NSEC || 468 rr_type == LDNS_RR_TYPE_NSEC3) { 469 /* XX check if is already set (and error?) */ 470 name->nsec = rr; 471 } else if (typecovered == LDNS_RR_TYPE_NSEC || 472 typecovered == LDNS_RR_TYPE_NSEC3) { 473 if (name->nsec_signatures) { 474 result = ldns_dnssec_rrs_add_rr(name->nsec_signatures, rr); 475 } else { 476 name->nsec_signatures = ldns_dnssec_rrs_new(); 477 name->nsec_signatures->rr = rr; 478 } 479 } else { 480 /* it's a 'normal' RR, add it to the right rrset */ 481 if (name->rrsets) { 482 result = ldns_dnssec_rrsets_add_rr(name->rrsets, rr); 483 } else { 484 name->rrsets = ldns_dnssec_rrsets_new(); 485 result = ldns_dnssec_rrsets_add_rr(name->rrsets, rr); 486 } 487 } 488 return result; 489 } 490 491 ldns_dnssec_rrsets * 492 ldns_dnssec_name_find_rrset(ldns_dnssec_name *name, 493 ldns_rr_type type) { 494 ldns_dnssec_rrsets *result; 495 496 result = name->rrsets; 497 while (result) { 498 if (result->type == type) { 499 return result; 500 } else { 501 result = result->next; 502 } 503 } 504 return NULL; 505 } 506 507 ldns_dnssec_rrsets * 508 ldns_dnssec_zone_find_rrset(ldns_dnssec_zone *zone, 509 ldns_rdf *dname, 510 ldns_rr_type type) 511 { 512 ldns_rbnode_t *node; 513 514 if (!zone || !dname) { 515 return NULL; 516 } 517 518 node = ldns_rbtree_search(zone->names, dname); 519 if (node) { 520 return ldns_dnssec_name_find_rrset((ldns_dnssec_name *)node->data, 521 type); 522 } else { 523 return NULL; 524 } 525 } 526 527 static void 528 ldns_dnssec_name_print_soa_fmt(FILE *out, const ldns_output_format *fmt, 529 ldns_dnssec_name *name, 530 bool show_soa) 531 { 532 if (name) { 533 if(name->rrsets) { 534 ldns_dnssec_rrsets_print_soa_fmt(out, fmt, 535 name->rrsets, true, show_soa); 536 } else if ((fmt->flags & LDNS_COMMENT_LAYOUT)) { 537 fprintf(out, ";; Empty nonterminal: "); 538 ldns_rdf_print(out, name->name); 539 fprintf(out, "\n"); 540 } 541 if(name->nsec) { 542 ldns_rr_print_fmt(out, fmt, name->nsec); 543 } 544 if (name->nsec_signatures) { 545 ldns_dnssec_rrs_print_fmt(out, fmt, 546 name->nsec_signatures); 547 } 548 } else if ((fmt->flags & LDNS_COMMENT_LAYOUT)) { 549 fprintf(out, "; <void>\n"); 550 } 551 } 552 553 554 void 555 ldns_dnssec_name_print_fmt(FILE *out, const ldns_output_format *fmt, 556 ldns_dnssec_name *name) 557 { 558 ldns_dnssec_name_print_soa_fmt(out, fmt, name, true); 559 } 560 561 void 562 ldns_dnssec_name_print(FILE *out, ldns_dnssec_name *name) 563 { 564 ldns_dnssec_name_print_fmt(out, ldns_output_format_default, name); 565 } 566 567 568 ldns_dnssec_zone * 569 ldns_dnssec_zone_new(void) 570 { 571 ldns_dnssec_zone *zone = LDNS_MALLOC(ldns_dnssec_zone); 572 if(!zone) return NULL; 573 zone->soa = NULL; 574 zone->names = NULL; 575 zone->hashed_names = NULL; 576 zone->_nsec3params = NULL; 577 578 return zone; 579 } 580 581 static bool 582 rr_is_rrsig_covering(ldns_rr* rr, ldns_rr_type t) 583 { 584 return ldns_rr_get_type(rr) == LDNS_RR_TYPE_RRSIG 585 && ldns_rdf2rr_type(ldns_rr_rrsig_typecovered(rr)) == t; 586 } 587 588 /* When the zone is first read into an list and then inserted into an 589 * ldns_dnssec_zone (rbtree) the nodes of the rbtree are allocated close (next) 590 * to each other. Because ldns-verify-zone (the only program that uses this 591 * function) uses the rbtree mostly for sequentual walking, this results 592 * in a speed increase (of 15% on linux) because we have less CPU-cache misses. 593 */ 594 #define FASTER_DNSSEC_ZONE_NEW_FRM_FP 1 /* Because of L2 cache efficiency */ 595 596 ldns_status 597 ldns_dnssec_zone_new_frm_fp_l(ldns_dnssec_zone** z, FILE* fp, ldns_rdf* origin, 598 uint32_t ttl, ldns_rr_class ATTR_UNUSED(c), int* line_nr) 599 { 600 ldns_rr* cur_rr; 601 size_t i; 602 603 ldns_rdf *my_origin = NULL; 604 ldns_rdf *my_prev = NULL; 605 606 ldns_dnssec_zone *newzone = ldns_dnssec_zone_new(); 607 /* when reading NSEC3s, there is a chance that we encounter nsecs 608 for empty nonterminals, whose nonterminals we cannot derive yet 609 because the needed information is to be read later. in that case 610 we keep a list of those nsec3's and retry to add them later */ 611 ldns_rr_list* todo_nsec3s = ldns_rr_list_new(); 612 ldns_rr_list* todo_nsec3_rrsigs = ldns_rr_list_new(); 613 614 ldns_status status = LDNS_STATUS_MEM_ERR; 615 616 #ifdef FASTER_DNSSEC_ZONE_NEW_FRM_FP 617 ldns_zone* zone = NULL; 618 if (ldns_zone_new_frm_fp_l(&zone, fp, origin,ttl, c, line_nr) 619 != LDNS_STATUS_OK) goto error; 620 #else 621 uint32_t my_ttl = ttl; 622 #endif 623 624 if (!newzone || !todo_nsec3s || !todo_nsec3_rrsigs ) goto error; 625 626 if (origin) { 627 if (!(my_origin = ldns_rdf_clone(origin))) goto error; 628 if (!(my_prev = ldns_rdf_clone(origin))) goto error; 629 } 630 631 #ifdef FASTER_DNSSEC_ZONE_NEW_FRM_FP 632 if (ldns_dnssec_zone_add_rr(newzone, ldns_zone_soa(zone)) 633 != LDNS_STATUS_OK) goto error; 634 635 for (i = 0; i < ldns_rr_list_rr_count(ldns_zone_rrs(zone)); i++) { 636 cur_rr = ldns_rr_list_rr(ldns_zone_rrs(zone), i); 637 status = LDNS_STATUS_OK; 638 #else 639 while (!feof(fp)) { 640 status = ldns_rr_new_frm_fp_l(&cur_rr, fp, &my_ttl, &my_origin, 641 &my_prev, line_nr); 642 643 #endif 644 switch (status) { 645 case LDNS_STATUS_OK: 646 647 status = ldns_dnssec_zone_add_rr(newzone, cur_rr); 648 if (status == 649 LDNS_STATUS_DNSSEC_NSEC3_ORIGINAL_NOT_FOUND) { 650 651 if (rr_is_rrsig_covering(cur_rr, 652 LDNS_RR_TYPE_NSEC3)){ 653 ldns_rr_list_push_rr(todo_nsec3_rrsigs, 654 cur_rr); 655 } else { 656 ldns_rr_list_push_rr(todo_nsec3s, 657 cur_rr); 658 } 659 status = LDNS_STATUS_OK; 660 661 } else if (status != LDNS_STATUS_OK) 662 goto error; 663 664 break; 665 666 667 case LDNS_STATUS_SYNTAX_EMPTY: /* empty line was seen */ 668 case LDNS_STATUS_SYNTAX_TTL: /* the ttl was set*/ 669 case LDNS_STATUS_SYNTAX_ORIGIN: /* the origin was set*/ 670 status = LDNS_STATUS_OK; 671 break; 672 673 case LDNS_STATUS_SYNTAX_INCLUDE:/* $include not implemented */ 674 status = LDNS_STATUS_SYNTAX_INCLUDE_ERR_NOTIMPL; 675 break; 676 677 default: 678 goto error; 679 } 680 } 681 682 if (ldns_rr_list_rr_count(todo_nsec3s) > 0) { 683 (void) ldns_dnssec_zone_add_empty_nonterminals(newzone); 684 for (i = 0; status == LDNS_STATUS_OK && 685 i < ldns_rr_list_rr_count(todo_nsec3s); i++) { 686 cur_rr = ldns_rr_list_rr(todo_nsec3s, i); 687 status = ldns_dnssec_zone_add_rr(newzone, cur_rr); 688 } 689 } 690 if (ldns_rr_list_rr_count(todo_nsec3_rrsigs) > 0) { 691 for (i = 0; status == LDNS_STATUS_OK && 692 i < ldns_rr_list_rr_count(todo_nsec3_rrsigs); 693 i++){ 694 cur_rr = ldns_rr_list_rr(todo_nsec3_rrsigs, i); 695 status = ldns_dnssec_zone_add_rr(newzone, cur_rr); 696 } 697 } 698 699 if (z) { 700 *z = newzone; 701 newzone = NULL; 702 } else { 703 ldns_dnssec_zone_free(newzone); 704 } 705 706 error: 707 #ifdef FASTER_DNSSEC_ZONE_NEW_FRM_FP 708 if (zone) { 709 ldns_zone_free(zone); 710 } 711 #endif 712 ldns_rr_list_free(todo_nsec3_rrsigs); 713 ldns_rr_list_free(todo_nsec3s); 714 715 if (my_origin) { 716 ldns_rdf_deep_free(my_origin); 717 } 718 if (my_prev) { 719 ldns_rdf_deep_free(my_prev); 720 } 721 if (newzone) { 722 ldns_dnssec_zone_free(newzone); 723 } 724 return status; 725 } 726 727 ldns_status 728 ldns_dnssec_zone_new_frm_fp(ldns_dnssec_zone** z, FILE* fp, ldns_rdf* origin, 729 uint32_t ttl, ldns_rr_class ATTR_UNUSED(c)) 730 { 731 return ldns_dnssec_zone_new_frm_fp_l(z, fp, origin, ttl, c, NULL); 732 } 733 734 static void 735 ldns_dnssec_name_node_free(ldns_rbnode_t *node, void *arg) { 736 (void) arg; 737 ldns_dnssec_name_free((ldns_dnssec_name *)node->data); 738 LDNS_FREE(node); 739 } 740 741 static void 742 ldns_dnssec_name_node_deep_free(ldns_rbnode_t *node, void *arg) { 743 (void) arg; 744 ldns_dnssec_name_deep_free((ldns_dnssec_name *)node->data); 745 LDNS_FREE(node); 746 } 747 748 void 749 ldns_dnssec_zone_free(ldns_dnssec_zone *zone) 750 { 751 if (zone) { 752 if (zone->names) { 753 /* destroy all name structures within the tree */ 754 ldns_traverse_postorder(zone->names, 755 ldns_dnssec_name_node_free, 756 NULL); 757 LDNS_FREE(zone->names); 758 } 759 LDNS_FREE(zone); 760 } 761 } 762 763 void 764 ldns_dnssec_zone_deep_free(ldns_dnssec_zone *zone) 765 { 766 if (zone) { 767 if (zone->names) { 768 /* destroy all name structures within the tree */ 769 ldns_traverse_postorder(zone->names, 770 ldns_dnssec_name_node_deep_free, 771 NULL); 772 LDNS_FREE(zone->names); 773 } 774 LDNS_FREE(zone); 775 } 776 } 777 778 /* use for dname comparison in tree */ 779 int 780 ldns_dname_compare_v(const void *a, const void *b) { 781 return ldns_dname_compare((ldns_rdf *)a, (ldns_rdf *)b); 782 } 783 784 static void 785 ldns_dnssec_name_make_hashed_name(ldns_dnssec_zone *zone, 786 ldns_dnssec_name* name, ldns_rr* nsec3rr); 787 788 static void 789 ldns_hashed_names_node_free(ldns_rbnode_t *node, void *arg) { 790 (void) arg; 791 LDNS_FREE(node); 792 } 793 794 static void 795 ldns_dnssec_zone_hashed_names_from_nsec3( 796 ldns_dnssec_zone* zone, ldns_rr* nsec3rr) 797 { 798 ldns_rbnode_t* current_node; 799 ldns_dnssec_name* current_name; 800 801 assert(zone != NULL); 802 assert(nsec3rr != NULL); 803 804 if (zone->hashed_names) { 805 ldns_traverse_postorder(zone->hashed_names, 806 ldns_hashed_names_node_free, NULL); 807 LDNS_FREE(zone->hashed_names); 808 } 809 zone->_nsec3params = nsec3rr; 810 811 /* So this is a NSEC3 zone. 812 * Calculate hashes for all names already in the zone 813 */ 814 zone->hashed_names = ldns_rbtree_create(ldns_dname_compare_v); 815 if (zone->hashed_names == NULL) { 816 return; 817 } 818 for ( current_node = ldns_rbtree_first(zone->names) 819 ; current_node != LDNS_RBTREE_NULL 820 ; current_node = ldns_rbtree_next(current_node) 821 ) { 822 current_name = (ldns_dnssec_name *) current_node->data; 823 ldns_dnssec_name_make_hashed_name(zone, current_name, nsec3rr); 824 825 } 826 } 827 828 static void 829 ldns_dnssec_name_make_hashed_name(ldns_dnssec_zone *zone, 830 ldns_dnssec_name* name, ldns_rr* nsec3rr) 831 { 832 ldns_rbnode_t* new_node; 833 834 assert(name != NULL); 835 if (! zone->_nsec3params) { 836 if (! nsec3rr) { 837 return; 838 } 839 ldns_dnssec_zone_hashed_names_from_nsec3(zone, nsec3rr); 840 841 } else if (! nsec3rr) { 842 nsec3rr = zone->_nsec3params; 843 } 844 name->hashed_name = ldns_nsec3_hash_name_frm_nsec3(nsec3rr, name->name); 845 846 /* Also store in zone->hashed_names */ 847 if ((new_node = LDNS_MALLOC(ldns_rbnode_t))) { 848 849 new_node->key = name->hashed_name; 850 new_node->data = name; 851 852 if (ldns_rbtree_insert(zone->hashed_names, new_node) == NULL) { 853 854 LDNS_FREE(new_node); 855 } 856 } 857 } 858 859 860 static ldns_rbnode_t * 861 ldns_dnssec_zone_find_nsec3_original(ldns_dnssec_zone *zone, ldns_rr *rr) { 862 ldns_rdf *hashed_name; 863 864 hashed_name = ldns_dname_label(ldns_rr_owner(rr), 0); 865 if (hashed_name == NULL) { 866 return NULL; 867 } 868 if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_NSEC3 && ! zone->_nsec3params){ 869 870 ldns_dnssec_zone_hashed_names_from_nsec3(zone, rr); 871 } 872 if (zone->hashed_names == NULL) { 873 ldns_rdf_deep_free(hashed_name); 874 return NULL; 875 } 876 return ldns_rbtree_search(zone->hashed_names, hashed_name); 877 } 878 879 ldns_status 880 ldns_dnssec_zone_add_rr(ldns_dnssec_zone *zone, ldns_rr *rr) 881 { 882 ldns_status result = LDNS_STATUS_OK; 883 ldns_dnssec_name *cur_name; 884 ldns_rbnode_t *cur_node; 885 ldns_rr_type type_covered = 0; 886 887 if (!zone || !rr) { 888 return LDNS_STATUS_ERR; 889 } 890 891 if (!zone->names) { 892 zone->names = ldns_rbtree_create(ldns_dname_compare_v); 893 if(!zone->names) return LDNS_STATUS_MEM_ERR; 894 } 895 896 /* we need the original of the hashed name if this is 897 an NSEC3, or an RRSIG that covers an NSEC3 */ 898 if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_RRSIG) { 899 type_covered = ldns_rdf2rr_type(ldns_rr_rrsig_typecovered(rr)); 900 } 901 if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_NSEC3 || 902 type_covered == LDNS_RR_TYPE_NSEC3) { 903 cur_node = ldns_dnssec_zone_find_nsec3_original(zone, rr); 904 if (!cur_node) { 905 return LDNS_STATUS_DNSSEC_NSEC3_ORIGINAL_NOT_FOUND; 906 } 907 } else { 908 cur_node = ldns_rbtree_search(zone->names, ldns_rr_owner(rr)); 909 } 910 if (!cur_node) { 911 /* add */ 912 cur_name = ldns_dnssec_name_new_frm_rr(rr); 913 if(!cur_name) return LDNS_STATUS_MEM_ERR; 914 cur_node = LDNS_MALLOC(ldns_rbnode_t); 915 if(!cur_node) { 916 ldns_dnssec_name_free(cur_name); 917 return LDNS_STATUS_MEM_ERR; 918 } 919 cur_node->key = ldns_rr_owner(rr); 920 cur_node->data = cur_name; 921 (void)ldns_rbtree_insert(zone->names, cur_node); 922 ldns_dnssec_name_make_hashed_name(zone, cur_name, NULL); 923 } else { 924 cur_name = (ldns_dnssec_name *) cur_node->data; 925 result = ldns_dnssec_name_add_rr(cur_name, rr); 926 } 927 if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_SOA) { 928 zone->soa = cur_name; 929 } 930 return result; 931 } 932 933 void 934 ldns_dnssec_zone_names_print_fmt(FILE *out, const ldns_output_format *fmt, 935 ldns_rbtree_t *tree, 936 bool print_soa) 937 { 938 ldns_rbnode_t *node; 939 ldns_dnssec_name *name; 940 941 node = ldns_rbtree_first(tree); 942 while (node != LDNS_RBTREE_NULL) { 943 name = (ldns_dnssec_name *) node->data; 944 ldns_dnssec_name_print_soa_fmt(out, fmt, name, print_soa); 945 if ((fmt->flags & LDNS_COMMENT_LAYOUT)) 946 fprintf(out, ";\n"); 947 node = ldns_rbtree_next(node); 948 } 949 } 950 951 void 952 ldns_dnssec_zone_names_print(FILE *out, ldns_rbtree_t *tree, bool print_soa) 953 { 954 ldns_dnssec_zone_names_print_fmt(out, ldns_output_format_default, 955 tree, print_soa); 956 } 957 958 void 959 ldns_dnssec_zone_print_fmt(FILE *out, const ldns_output_format *fmt, 960 ldns_dnssec_zone *zone) 961 { 962 if (zone) { 963 if (zone->soa) { 964 if ((fmt->flags & LDNS_COMMENT_LAYOUT)) { 965 fprintf(out, ";; Zone: "); 966 ldns_rdf_print(out, ldns_dnssec_name_name( 967 zone->soa)); 968 fprintf(out, "\n;\n"); 969 } 970 ldns_dnssec_rrsets_print_fmt(out, fmt, 971 ldns_dnssec_name_find_rrset( 972 zone->soa, 973 LDNS_RR_TYPE_SOA), 974 false); 975 if ((fmt->flags & LDNS_COMMENT_LAYOUT)) 976 fprintf(out, ";\n"); 977 } 978 979 if (zone->names) { 980 ldns_dnssec_zone_names_print_fmt(out, fmt, 981 zone->names, false); 982 } 983 } 984 } 985 986 void 987 ldns_dnssec_zone_print(FILE *out, ldns_dnssec_zone *zone) 988 { 989 ldns_dnssec_zone_print_fmt(out, ldns_output_format_default, zone); 990 } 991 992 ldns_status 993 ldns_dnssec_zone_add_empty_nonterminals(ldns_dnssec_zone *zone) 994 { 995 ldns_dnssec_name *new_name; 996 ldns_rdf *cur_name; 997 ldns_rdf *next_name; 998 ldns_rbnode_t *cur_node, *next_node, *new_node; 999 1000 /* for the detection */ 1001 uint16_t i, cur_label_count, next_label_count; 1002 uint16_t soa_label_count = 0; 1003 ldns_rdf *l1, *l2; 1004 int lpos; 1005 1006 if (!zone) { 1007 return LDNS_STATUS_ERR; 1008 } 1009 if (zone->soa && zone->soa->name) { 1010 soa_label_count = ldns_dname_label_count(zone->soa->name); 1011 } 1012 1013 cur_node = ldns_rbtree_first(zone->names); 1014 while (cur_node != LDNS_RBTREE_NULL) { 1015 next_node = ldns_rbtree_next(cur_node); 1016 1017 /* skip glue */ 1018 while (next_node != LDNS_RBTREE_NULL && 1019 next_node->data && 1020 ((ldns_dnssec_name *)next_node->data)->is_glue 1021 ) { 1022 next_node = ldns_rbtree_next(next_node); 1023 } 1024 1025 if (next_node == LDNS_RBTREE_NULL) { 1026 next_node = ldns_rbtree_first(zone->names); 1027 } 1028 if (! cur_node->data || ! next_node->data) { 1029 return LDNS_STATUS_ERR; 1030 } 1031 cur_name = ((ldns_dnssec_name *)cur_node->data)->name; 1032 next_name = ((ldns_dnssec_name *)next_node->data)->name; 1033 cur_label_count = ldns_dname_label_count(cur_name); 1034 next_label_count = ldns_dname_label_count(next_name); 1035 1036 /* Since the names are in canonical order, we can 1037 * recognize empty non-terminals by their labels; 1038 * every label after the first one on the next owner 1039 * name is a non-terminal if it either does not exist 1040 * in the current name or is different from the same 1041 * label in the current name (counting from the end) 1042 */ 1043 for (i = 1; i < next_label_count - soa_label_count; i++) { 1044 lpos = (int)cur_label_count - (int)next_label_count + (int)i; 1045 if (lpos >= 0) { 1046 l1 = ldns_dname_clone_from(cur_name, (uint8_t)lpos); 1047 } else { 1048 l1 = NULL; 1049 } 1050 l2 = ldns_dname_clone_from(next_name, i); 1051 1052 if (!l1 || ldns_dname_compare(l1, l2) != 0) { 1053 /* We have an empty nonterminal, add it to the 1054 * tree 1055 */ 1056 new_name = ldns_dnssec_name_new(); 1057 if (!new_name) { 1058 return LDNS_STATUS_MEM_ERR; 1059 } 1060 new_name->name = ldns_dname_clone_from(next_name, 1061 i); 1062 if (!new_name->name) { 1063 ldns_dnssec_name_free(new_name); 1064 return LDNS_STATUS_MEM_ERR; 1065 } 1066 new_name->name_alloced = true; 1067 new_node = LDNS_MALLOC(ldns_rbnode_t); 1068 if (!new_node) { 1069 ldns_dnssec_name_free(new_name); 1070 return LDNS_STATUS_MEM_ERR; 1071 } 1072 new_node->key = new_name->name; 1073 new_node->data = new_name; 1074 (void)ldns_rbtree_insert(zone->names, new_node); 1075 ldns_dnssec_name_make_hashed_name( 1076 zone, new_name, NULL); 1077 } 1078 ldns_rdf_deep_free(l1); 1079 ldns_rdf_deep_free(l2); 1080 } 1081 1082 /* we might have inserted a new node after 1083 * the current one so we can't just use next() 1084 */ 1085 if (next_node != ldns_rbtree_first(zone->names)) { 1086 cur_node = next_node; 1087 } else { 1088 cur_node = LDNS_RBTREE_NULL; 1089 } 1090 } 1091 return LDNS_STATUS_OK; 1092 } 1093 1094 bool 1095 ldns_dnssec_zone_is_nsec3_optout(ldns_dnssec_zone* zone) 1096 { 1097 ldns_rr* nsec3; 1098 ldns_rbnode_t* node; 1099 1100 if (ldns_dnssec_name_find_rrset(zone->soa, LDNS_RR_TYPE_NSEC3PARAM)) { 1101 node = ldns_rbtree_first(zone->names); 1102 while (node != LDNS_RBTREE_NULL) { 1103 nsec3 = ((ldns_dnssec_name*)node->data)->nsec; 1104 if (nsec3 &&ldns_rr_get_type(nsec3) 1105 == LDNS_RR_TYPE_NSEC3 && 1106 ldns_nsec3_optout(nsec3)) { 1107 return true; 1108 } 1109 node = ldns_rbtree_next(node); 1110 } 1111 } 1112 return false; 1113 } 1114