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