1238104Sdes/* 2238104Sdes * special zone file structures and functions for better dnssec handling 3238104Sdes */ 4238104Sdes 5238104Sdes#include <ldns/config.h> 6238104Sdes 7238104Sdes#include <ldns/ldns.h> 8238104Sdes 9238104Sdesldns_dnssec_rrs * 10246827Sdesldns_dnssec_rrs_new(void) 11238104Sdes{ 12238104Sdes ldns_dnssec_rrs *new_rrs; 13238104Sdes new_rrs = LDNS_MALLOC(ldns_dnssec_rrs); 14238104Sdes if(!new_rrs) return NULL; 15238104Sdes new_rrs->rr = NULL; 16238104Sdes new_rrs->next = NULL; 17238104Sdes return new_rrs; 18238104Sdes} 19238104Sdes 20238104SdesINLINE void 21238104Sdesldns_dnssec_rrs_free_internal(ldns_dnssec_rrs *rrs, int deep) 22238104Sdes{ 23238104Sdes ldns_dnssec_rrs *next; 24238104Sdes while (rrs) { 25238104Sdes next = rrs->next; 26238104Sdes if (deep) { 27238104Sdes ldns_rr_free(rrs->rr); 28238104Sdes } 29238104Sdes LDNS_FREE(rrs); 30238104Sdes rrs = next; 31238104Sdes } 32238104Sdes} 33238104Sdes 34238104Sdesvoid 35238104Sdesldns_dnssec_rrs_free(ldns_dnssec_rrs *rrs) 36238104Sdes{ 37238104Sdes ldns_dnssec_rrs_free_internal(rrs, 0); 38238104Sdes} 39238104Sdes 40238104Sdesvoid 41238104Sdesldns_dnssec_rrs_deep_free(ldns_dnssec_rrs *rrs) 42238104Sdes{ 43238104Sdes ldns_dnssec_rrs_free_internal(rrs, 1); 44238104Sdes} 45238104Sdes 46238104Sdesldns_status 47238104Sdesldns_dnssec_rrs_add_rr(ldns_dnssec_rrs *rrs, ldns_rr *rr) 48238104Sdes{ 49238104Sdes int cmp; 50238104Sdes ldns_dnssec_rrs *new_rrs; 51238104Sdes if (!rrs || !rr) { 52238104Sdes return LDNS_STATUS_ERR; 53238104Sdes } 54238104Sdes 55238104Sdes /* this could be done more efficiently; name and type should already 56238104Sdes be equal */ 57269257Sdes cmp = ldns_rr_compare(rrs->rr, rr); 58269257Sdes if (cmp < 0) { 59238104Sdes if (rrs->next) { 60238104Sdes return ldns_dnssec_rrs_add_rr(rrs->next, rr); 61238104Sdes } else { 62238104Sdes new_rrs = ldns_dnssec_rrs_new(); 63238104Sdes new_rrs->rr = rr; 64238104Sdes rrs->next = new_rrs; 65238104Sdes } 66238104Sdes } else if (cmp > 0) { 67238104Sdes /* put the current old rr in the new next, put the new 68238104Sdes rr in the current container */ 69238104Sdes new_rrs = ldns_dnssec_rrs_new(); 70238104Sdes new_rrs->rr = rrs->rr; 71238104Sdes new_rrs->next = rrs->next; 72238104Sdes rrs->rr = rr; 73238104Sdes rrs->next = new_rrs; 74238104Sdes } 75269257Sdes /* Silently ignore equal rr's */ 76238104Sdes return LDNS_STATUS_OK; 77238104Sdes} 78238104Sdes 79238104Sdesvoid 80238104Sdesldns_dnssec_rrs_print_fmt(FILE *out, const ldns_output_format *fmt, 81238104Sdes ldns_dnssec_rrs *rrs) 82238104Sdes{ 83238104Sdes if (!rrs) { 84238104Sdes if ((fmt->flags & LDNS_COMMENT_LAYOUT)) 85238104Sdes fprintf(out, "; <void>"); 86238104Sdes } else { 87238104Sdes if (rrs->rr) { 88238104Sdes ldns_rr_print_fmt(out, fmt, rrs->rr); 89238104Sdes } 90238104Sdes if (rrs->next) { 91238104Sdes ldns_dnssec_rrs_print_fmt(out, fmt, rrs->next); 92238104Sdes } 93238104Sdes } 94238104Sdes} 95238104Sdes 96238104Sdesvoid 97238104Sdesldns_dnssec_rrs_print(FILE *out, ldns_dnssec_rrs *rrs) 98238104Sdes{ 99238104Sdes ldns_dnssec_rrs_print_fmt(out, ldns_output_format_default, rrs); 100238104Sdes} 101238104Sdes 102238104Sdes 103238104Sdesldns_dnssec_rrsets * 104246827Sdesldns_dnssec_rrsets_new(void) 105238104Sdes{ 106238104Sdes ldns_dnssec_rrsets *new_rrsets; 107238104Sdes new_rrsets = LDNS_MALLOC(ldns_dnssec_rrsets); 108238104Sdes if(!new_rrsets) return NULL; 109238104Sdes new_rrsets->rrs = NULL; 110238104Sdes new_rrsets->type = 0; 111238104Sdes new_rrsets->signatures = NULL; 112238104Sdes new_rrsets->next = NULL; 113238104Sdes return new_rrsets; 114238104Sdes} 115238104Sdes 116238104SdesINLINE void 117238104Sdesldns_dnssec_rrsets_free_internal(ldns_dnssec_rrsets *rrsets, int deep) 118238104Sdes{ 119238104Sdes if (rrsets) { 120238104Sdes if (rrsets->rrs) { 121238104Sdes ldns_dnssec_rrs_free_internal(rrsets->rrs, deep); 122238104Sdes } 123238104Sdes if (rrsets->next) { 124238104Sdes ldns_dnssec_rrsets_free_internal(rrsets->next, deep); 125238104Sdes } 126238104Sdes if (rrsets->signatures) { 127238104Sdes ldns_dnssec_rrs_free_internal(rrsets->signatures, deep); 128238104Sdes } 129238104Sdes LDNS_FREE(rrsets); 130238104Sdes } 131238104Sdes} 132238104Sdes 133238104Sdesvoid 134238104Sdesldns_dnssec_rrsets_free(ldns_dnssec_rrsets *rrsets) 135238104Sdes{ 136238104Sdes ldns_dnssec_rrsets_free_internal(rrsets, 0); 137238104Sdes} 138238104Sdes 139238104Sdesvoid 140238104Sdesldns_dnssec_rrsets_deep_free(ldns_dnssec_rrsets *rrsets) 141238104Sdes{ 142238104Sdes ldns_dnssec_rrsets_free_internal(rrsets, 1); 143238104Sdes} 144238104Sdes 145238104Sdesldns_rr_type 146238104Sdesldns_dnssec_rrsets_type(ldns_dnssec_rrsets *rrsets) 147238104Sdes{ 148238104Sdes if (rrsets) { 149238104Sdes return rrsets->type; 150238104Sdes } else { 151238104Sdes return 0; 152238104Sdes } 153238104Sdes} 154238104Sdes 155238104Sdesldns_status 156238104Sdesldns_dnssec_rrsets_set_type(ldns_dnssec_rrsets *rrsets, 157238104Sdes ldns_rr_type type) 158238104Sdes{ 159238104Sdes if (rrsets) { 160238104Sdes rrsets->type = type; 161238104Sdes return LDNS_STATUS_OK; 162238104Sdes } 163238104Sdes return LDNS_STATUS_ERR; 164238104Sdes} 165238104Sdes 166246827Sdesstatic ldns_dnssec_rrsets * 167238104Sdesldns_dnssec_rrsets_new_frm_rr(ldns_rr *rr) 168238104Sdes{ 169238104Sdes ldns_dnssec_rrsets *new_rrsets; 170238104Sdes ldns_rr_type rr_type; 171238104Sdes bool rrsig; 172238104Sdes 173238104Sdes new_rrsets = ldns_dnssec_rrsets_new(); 174238104Sdes rr_type = ldns_rr_get_type(rr); 175238104Sdes if (rr_type == LDNS_RR_TYPE_RRSIG) { 176238104Sdes rrsig = true; 177238104Sdes rr_type = ldns_rdf2rr_type(ldns_rr_rrsig_typecovered(rr)); 178238104Sdes } else { 179238104Sdes rrsig = false; 180238104Sdes } 181238104Sdes if (!rrsig) { 182238104Sdes new_rrsets->rrs = ldns_dnssec_rrs_new(); 183238104Sdes new_rrsets->rrs->rr = rr; 184238104Sdes } else { 185238104Sdes new_rrsets->signatures = ldns_dnssec_rrs_new(); 186238104Sdes new_rrsets->signatures->rr = rr; 187238104Sdes } 188238104Sdes new_rrsets->type = rr_type; 189238104Sdes return new_rrsets; 190238104Sdes} 191238104Sdes 192238104Sdesldns_status 193238104Sdesldns_dnssec_rrsets_add_rr(ldns_dnssec_rrsets *rrsets, ldns_rr *rr) 194238104Sdes{ 195238104Sdes ldns_dnssec_rrsets *new_rrsets; 196238104Sdes ldns_rr_type rr_type; 197238104Sdes bool rrsig = false; 198238104Sdes ldns_status result = LDNS_STATUS_OK; 199238104Sdes 200238104Sdes if (!rrsets || !rr) { 201238104Sdes return LDNS_STATUS_ERR; 202238104Sdes } 203238104Sdes 204238104Sdes rr_type = ldns_rr_get_type(rr); 205238104Sdes 206238104Sdes if (rr_type == LDNS_RR_TYPE_RRSIG) { 207238104Sdes rrsig = true; 208238104Sdes rr_type = ldns_rdf2rr_type(ldns_rr_rrsig_typecovered(rr)); 209238104Sdes } 210238104Sdes 211238104Sdes if (!rrsets->rrs && rrsets->type == 0 && !rrsets->signatures) { 212238104Sdes if (!rrsig) { 213238104Sdes rrsets->rrs = ldns_dnssec_rrs_new(); 214238104Sdes rrsets->rrs->rr = rr; 215238104Sdes rrsets->type = rr_type; 216238104Sdes } else { 217238104Sdes rrsets->signatures = ldns_dnssec_rrs_new(); 218238104Sdes rrsets->signatures->rr = rr; 219238104Sdes rrsets->type = rr_type; 220238104Sdes } 221238104Sdes return LDNS_STATUS_OK; 222238104Sdes } 223238104Sdes 224238104Sdes if (rr_type > ldns_dnssec_rrsets_type(rrsets)) { 225238104Sdes if (rrsets->next) { 226238104Sdes result = ldns_dnssec_rrsets_add_rr(rrsets->next, rr); 227238104Sdes } else { 228238104Sdes new_rrsets = ldns_dnssec_rrsets_new_frm_rr(rr); 229238104Sdes rrsets->next = new_rrsets; 230238104Sdes } 231238104Sdes } else if (rr_type < ldns_dnssec_rrsets_type(rrsets)) { 232238104Sdes /* move the current one into the new next, 233238104Sdes replace field of current with data from new rr */ 234238104Sdes new_rrsets = ldns_dnssec_rrsets_new(); 235238104Sdes new_rrsets->rrs = rrsets->rrs; 236238104Sdes new_rrsets->type = rrsets->type; 237238104Sdes new_rrsets->signatures = rrsets->signatures; 238238104Sdes new_rrsets->next = rrsets->next; 239238104Sdes if (!rrsig) { 240238104Sdes rrsets->rrs = ldns_dnssec_rrs_new(); 241238104Sdes rrsets->rrs->rr = rr; 242238104Sdes rrsets->signatures = NULL; 243238104Sdes } else { 244238104Sdes rrsets->rrs = NULL; 245238104Sdes rrsets->signatures = ldns_dnssec_rrs_new(); 246238104Sdes rrsets->signatures->rr = rr; 247238104Sdes } 248238104Sdes rrsets->type = rr_type; 249238104Sdes rrsets->next = new_rrsets; 250238104Sdes } else { 251238104Sdes /* equal, add to current rrsets */ 252238104Sdes if (rrsig) { 253238104Sdes if (rrsets->signatures) { 254238104Sdes result = ldns_dnssec_rrs_add_rr(rrsets->signatures, rr); 255238104Sdes } else { 256238104Sdes rrsets->signatures = ldns_dnssec_rrs_new(); 257238104Sdes rrsets->signatures->rr = rr; 258238104Sdes } 259238104Sdes } else { 260238104Sdes if (rrsets->rrs) { 261238104Sdes result = ldns_dnssec_rrs_add_rr(rrsets->rrs, rr); 262238104Sdes } else { 263238104Sdes rrsets->rrs = ldns_dnssec_rrs_new(); 264238104Sdes rrsets->rrs->rr = rr; 265238104Sdes } 266238104Sdes } 267238104Sdes } 268238104Sdes 269238104Sdes return result; 270238104Sdes} 271238104Sdes 272246827Sdesstatic void 273238104Sdesldns_dnssec_rrsets_print_soa_fmt(FILE *out, const ldns_output_format *fmt, 274238104Sdes ldns_dnssec_rrsets *rrsets, 275238104Sdes bool follow, 276238104Sdes bool show_soa) 277238104Sdes{ 278238104Sdes if (!rrsets) { 279238104Sdes if ((fmt->flags & LDNS_COMMENT_LAYOUT)) 280238104Sdes fprintf(out, "; <void>\n"); 281238104Sdes } else { 282238104Sdes if (rrsets->rrs && 283238104Sdes (show_soa || 284238104Sdes ldns_rr_get_type(rrsets->rrs->rr) != LDNS_RR_TYPE_SOA 285238104Sdes ) 286238104Sdes ) { 287238104Sdes ldns_dnssec_rrs_print_fmt(out, fmt, rrsets->rrs); 288238104Sdes if (rrsets->signatures) { 289238104Sdes ldns_dnssec_rrs_print_fmt(out, fmt, 290238104Sdes rrsets->signatures); 291238104Sdes } 292238104Sdes } 293238104Sdes if (follow && rrsets->next) { 294238104Sdes ldns_dnssec_rrsets_print_soa_fmt(out, fmt, 295238104Sdes rrsets->next, follow, show_soa); 296238104Sdes } 297238104Sdes } 298238104Sdes} 299238104Sdes 300238104Sdes 301238104Sdesvoid 302238104Sdesldns_dnssec_rrsets_print_fmt(FILE *out, const ldns_output_format *fmt, 303238104Sdes ldns_dnssec_rrsets *rrsets, 304238104Sdes bool follow) 305238104Sdes{ 306238104Sdes ldns_dnssec_rrsets_print_soa_fmt(out, fmt, rrsets, follow, true); 307238104Sdes} 308238104Sdes 309238104Sdesvoid 310238104Sdesldns_dnssec_rrsets_print(FILE *out, ldns_dnssec_rrsets *rrsets, bool follow) 311238104Sdes{ 312238104Sdes ldns_dnssec_rrsets_print_fmt(out, ldns_output_format_default, 313238104Sdes rrsets, follow); 314238104Sdes} 315238104Sdes 316238104Sdesldns_dnssec_name * 317246827Sdesldns_dnssec_name_new(void) 318238104Sdes{ 319238104Sdes ldns_dnssec_name *new_name; 320238104Sdes 321238104Sdes new_name = LDNS_CALLOC(ldns_dnssec_name, 1); 322238104Sdes if (!new_name) { 323238104Sdes return NULL; 324238104Sdes } 325238104Sdes /* 326238104Sdes * not needed anymore because CALLOC initalizes everything to zero. 327238104Sdes 328238104Sdes new_name->name = NULL; 329238104Sdes new_name->rrsets = NULL; 330238104Sdes new_name->name_alloced = false; 331238104Sdes new_name->nsec = NULL; 332238104Sdes new_name->nsec_signatures = NULL; 333238104Sdes 334238104Sdes new_name->is_glue = false; 335238104Sdes new_name->hashed_name = NULL; 336238104Sdes 337238104Sdes */ 338238104Sdes return new_name; 339238104Sdes} 340238104Sdes 341238104Sdesldns_dnssec_name * 342238104Sdesldns_dnssec_name_new_frm_rr(ldns_rr *rr) 343238104Sdes{ 344238104Sdes ldns_dnssec_name *new_name = ldns_dnssec_name_new(); 345238104Sdes 346238104Sdes new_name->name = ldns_rr_owner(rr); 347238104Sdes if(ldns_dnssec_name_add_rr(new_name, rr) != LDNS_STATUS_OK) { 348238104Sdes ldns_dnssec_name_free(new_name); 349238104Sdes return NULL; 350238104Sdes } 351238104Sdes 352238104Sdes return new_name; 353238104Sdes} 354238104Sdes 355238104SdesINLINE void 356238104Sdesldns_dnssec_name_free_internal(ldns_dnssec_name *name, 357238104Sdes int deep) 358238104Sdes{ 359238104Sdes if (name) { 360238104Sdes if (name->name_alloced) { 361238104Sdes ldns_rdf_deep_free(name->name); 362238104Sdes } 363238104Sdes if (name->rrsets) { 364238104Sdes ldns_dnssec_rrsets_free_internal(name->rrsets, deep); 365238104Sdes } 366238104Sdes if (name->nsec && deep) { 367238104Sdes ldns_rr_free(name->nsec); 368238104Sdes } 369238104Sdes if (name->nsec_signatures) { 370238104Sdes ldns_dnssec_rrs_free_internal(name->nsec_signatures, deep); 371238104Sdes } 372238104Sdes if (name->hashed_name) { 373238104Sdes if (deep) { 374238104Sdes ldns_rdf_deep_free(name->hashed_name); 375238104Sdes } 376238104Sdes } 377238104Sdes LDNS_FREE(name); 378238104Sdes } 379238104Sdes} 380238104Sdes 381238104Sdesvoid 382238104Sdesldns_dnssec_name_free(ldns_dnssec_name *name) 383238104Sdes{ 384238104Sdes ldns_dnssec_name_free_internal(name, 0); 385238104Sdes} 386238104Sdes 387238104Sdesvoid 388238104Sdesldns_dnssec_name_deep_free(ldns_dnssec_name *name) 389238104Sdes{ 390238104Sdes ldns_dnssec_name_free_internal(name, 1); 391238104Sdes} 392238104Sdes 393238104Sdesldns_rdf * 394238104Sdesldns_dnssec_name_name(ldns_dnssec_name *name) 395238104Sdes{ 396238104Sdes if (name) { 397238104Sdes return name->name; 398238104Sdes } 399238104Sdes return NULL; 400238104Sdes} 401238104Sdes 402238104Sdesbool 403238104Sdesldns_dnssec_name_is_glue(ldns_dnssec_name *name) 404238104Sdes{ 405238104Sdes if (name) { 406238104Sdes return name->is_glue; 407238104Sdes } 408238104Sdes return false; 409238104Sdes} 410238104Sdes 411238104Sdesvoid 412238104Sdesldns_dnssec_name_set_name(ldns_dnssec_name *rrset, 413238104Sdes ldns_rdf *dname) 414238104Sdes{ 415238104Sdes if (rrset && dname) { 416238104Sdes rrset->name = dname; 417238104Sdes } 418238104Sdes} 419238104Sdes 420238104Sdes 421238104Sdesvoid 422238104Sdesldns_dnssec_name_set_nsec(ldns_dnssec_name *rrset, ldns_rr *nsec) 423238104Sdes{ 424238104Sdes if (rrset && nsec) { 425238104Sdes rrset->nsec = nsec; 426238104Sdes } 427238104Sdes} 428238104Sdes 429238104Sdesint 430238104Sdesldns_dnssec_name_cmp(const void *a, const void *b) 431238104Sdes{ 432238104Sdes ldns_dnssec_name *na = (ldns_dnssec_name *) a; 433238104Sdes ldns_dnssec_name *nb = (ldns_dnssec_name *) b; 434238104Sdes 435238104Sdes if (na && nb) { 436238104Sdes return ldns_dname_compare(ldns_dnssec_name_name(na), 437238104Sdes ldns_dnssec_name_name(nb)); 438238104Sdes } else if (na) { 439238104Sdes return 1; 440238104Sdes } else if (nb) { 441238104Sdes return -1; 442238104Sdes } else { 443238104Sdes return 0; 444238104Sdes } 445238104Sdes} 446238104Sdes 447238104Sdesldns_status 448238104Sdesldns_dnssec_name_add_rr(ldns_dnssec_name *name, 449238104Sdes ldns_rr *rr) 450238104Sdes{ 451238104Sdes ldns_status result = LDNS_STATUS_OK; 452238104Sdes ldns_rr_type rr_type; 453238104Sdes ldns_rr_type typecovered = 0; 454238104Sdes 455238104Sdes /* special handling for NSEC3 and NSECX covering RRSIGS */ 456238104Sdes 457238104Sdes if (!name || !rr) { 458238104Sdes return LDNS_STATUS_ERR; 459238104Sdes } 460238104Sdes 461238104Sdes rr_type = ldns_rr_get_type(rr); 462238104Sdes 463238104Sdes if (rr_type == LDNS_RR_TYPE_RRSIG) { 464238104Sdes typecovered = ldns_rdf2rr_type(ldns_rr_rrsig_typecovered(rr)); 465238104Sdes } 466238104Sdes 467238104Sdes if (rr_type == LDNS_RR_TYPE_NSEC || 468238104Sdes rr_type == LDNS_RR_TYPE_NSEC3) { 469238104Sdes /* XX check if is already set (and error?) */ 470238104Sdes name->nsec = rr; 471238104Sdes } else if (typecovered == LDNS_RR_TYPE_NSEC || 472238104Sdes typecovered == LDNS_RR_TYPE_NSEC3) { 473238104Sdes if (name->nsec_signatures) { 474238104Sdes result = ldns_dnssec_rrs_add_rr(name->nsec_signatures, rr); 475238104Sdes } else { 476238104Sdes name->nsec_signatures = ldns_dnssec_rrs_new(); 477238104Sdes name->nsec_signatures->rr = rr; 478238104Sdes } 479238104Sdes } else { 480238104Sdes /* it's a 'normal' RR, add it to the right rrset */ 481238104Sdes if (name->rrsets) { 482238104Sdes result = ldns_dnssec_rrsets_add_rr(name->rrsets, rr); 483238104Sdes } else { 484238104Sdes name->rrsets = ldns_dnssec_rrsets_new(); 485238104Sdes result = ldns_dnssec_rrsets_add_rr(name->rrsets, rr); 486238104Sdes } 487238104Sdes } 488238104Sdes return result; 489238104Sdes} 490238104Sdes 491238104Sdesldns_dnssec_rrsets * 492238104Sdesldns_dnssec_name_find_rrset(ldns_dnssec_name *name, 493238104Sdes ldns_rr_type type) { 494238104Sdes ldns_dnssec_rrsets *result; 495238104Sdes 496238104Sdes result = name->rrsets; 497238104Sdes while (result) { 498238104Sdes if (result->type == type) { 499238104Sdes return result; 500238104Sdes } else { 501238104Sdes result = result->next; 502238104Sdes } 503238104Sdes } 504238104Sdes return NULL; 505238104Sdes} 506238104Sdes 507238104Sdesldns_dnssec_rrsets * 508238104Sdesldns_dnssec_zone_find_rrset(ldns_dnssec_zone *zone, 509238104Sdes ldns_rdf *dname, 510238104Sdes ldns_rr_type type) 511238104Sdes{ 512238104Sdes ldns_rbnode_t *node; 513238104Sdes 514238104Sdes if (!zone || !dname) { 515238104Sdes return NULL; 516238104Sdes } 517238104Sdes 518238104Sdes node = ldns_rbtree_search(zone->names, dname); 519238104Sdes if (node) { 520238104Sdes return ldns_dnssec_name_find_rrset((ldns_dnssec_name *)node->data, 521238104Sdes type); 522238104Sdes } else { 523238104Sdes return NULL; 524238104Sdes } 525238104Sdes} 526238104Sdes 527246827Sdesstatic void 528238104Sdesldns_dnssec_name_print_soa_fmt(FILE *out, const ldns_output_format *fmt, 529238104Sdes ldns_dnssec_name *name, 530238104Sdes bool show_soa) 531238104Sdes{ 532238104Sdes if (name) { 533238104Sdes if(name->rrsets) { 534238104Sdes ldns_dnssec_rrsets_print_soa_fmt(out, fmt, 535238104Sdes name->rrsets, true, show_soa); 536238104Sdes } else if ((fmt->flags & LDNS_COMMENT_LAYOUT)) { 537238104Sdes fprintf(out, ";; Empty nonterminal: "); 538238104Sdes ldns_rdf_print(out, name->name); 539238104Sdes fprintf(out, "\n"); 540238104Sdes } 541238104Sdes if(name->nsec) { 542238104Sdes ldns_rr_print_fmt(out, fmt, name->nsec); 543238104Sdes } 544238104Sdes if (name->nsec_signatures) { 545238104Sdes ldns_dnssec_rrs_print_fmt(out, fmt, 546238104Sdes name->nsec_signatures); 547238104Sdes } 548238104Sdes } else if ((fmt->flags & LDNS_COMMENT_LAYOUT)) { 549238104Sdes fprintf(out, "; <void>\n"); 550238104Sdes } 551238104Sdes} 552238104Sdes 553238104Sdes 554238104Sdesvoid 555238104Sdesldns_dnssec_name_print_fmt(FILE *out, const ldns_output_format *fmt, 556238104Sdes ldns_dnssec_name *name) 557238104Sdes{ 558238104Sdes ldns_dnssec_name_print_soa_fmt(out, fmt, name, true); 559238104Sdes} 560238104Sdes 561238104Sdesvoid 562238104Sdesldns_dnssec_name_print(FILE *out, ldns_dnssec_name *name) 563238104Sdes{ 564238104Sdes ldns_dnssec_name_print_fmt(out, ldns_output_format_default, name); 565238104Sdes} 566238104Sdes 567238104Sdes 568238104Sdesldns_dnssec_zone * 569246827Sdesldns_dnssec_zone_new(void) 570238104Sdes{ 571238104Sdes ldns_dnssec_zone *zone = LDNS_MALLOC(ldns_dnssec_zone); 572238104Sdes if(!zone) return NULL; 573238104Sdes zone->soa = NULL; 574238104Sdes zone->names = NULL; 575269257Sdes zone->hashed_names = NULL; 576269257Sdes zone->_nsec3params = NULL; 577238104Sdes 578238104Sdes return zone; 579238104Sdes} 580238104Sdes 581238104Sdesstatic bool 582238104Sdesrr_is_rrsig_covering(ldns_rr* rr, ldns_rr_type t) 583238104Sdes{ 584238104Sdes return ldns_rr_get_type(rr) == LDNS_RR_TYPE_RRSIG 585238104Sdes && ldns_rdf2rr_type(ldns_rr_rrsig_typecovered(rr)) == t; 586238104Sdes} 587238104Sdes 588238104Sdes/* When the zone is first read into an list and then inserted into an 589238104Sdes * ldns_dnssec_zone (rbtree) the nodes of the rbtree are allocated close (next) 590238104Sdes * to each other. Because ldns-verify-zone (the only program that uses this 591238104Sdes * function) uses the rbtree mostly for sequentual walking, this results 592238104Sdes * in a speed increase (of 15% on linux) because we have less CPU-cache misses. 593238104Sdes */ 594238104Sdes#define FASTER_DNSSEC_ZONE_NEW_FRM_FP 1 /* Because of L2 cache efficiency */ 595238104Sdes 596238104Sdesldns_status 597238104Sdesldns_dnssec_zone_new_frm_fp_l(ldns_dnssec_zone** z, FILE* fp, ldns_rdf* origin, 598238104Sdes uint32_t ttl, ldns_rr_class ATTR_UNUSED(c), int* line_nr) 599238104Sdes{ 600238104Sdes ldns_rr* cur_rr; 601238104Sdes size_t i; 602238104Sdes 603238104Sdes ldns_rdf *my_origin = NULL; 604238104Sdes ldns_rdf *my_prev = NULL; 605238104Sdes 606238104Sdes ldns_dnssec_zone *newzone = ldns_dnssec_zone_new(); 607238104Sdes /* when reading NSEC3s, there is a chance that we encounter nsecs 608238104Sdes for empty nonterminals, whose nonterminals we cannot derive yet 609238104Sdes because the needed information is to be read later. in that case 610238104Sdes we keep a list of those nsec3's and retry to add them later */ 611238104Sdes ldns_rr_list* todo_nsec3s = ldns_rr_list_new(); 612238104Sdes ldns_rr_list* todo_nsec3_rrsigs = ldns_rr_list_new(); 613238104Sdes 614238104Sdes ldns_status status = LDNS_STATUS_MEM_ERR; 615238104Sdes 616238104Sdes#ifdef FASTER_DNSSEC_ZONE_NEW_FRM_FP 617238104Sdes ldns_zone* zone = NULL; 618238104Sdes if (ldns_zone_new_frm_fp_l(&zone, fp, origin,ttl, c, line_nr) 619238104Sdes != LDNS_STATUS_OK) goto error; 620238104Sdes#else 621238104Sdes uint32_t my_ttl = ttl; 622238104Sdes#endif 623238104Sdes 624238104Sdes if (!newzone || !todo_nsec3s || !todo_nsec3_rrsigs ) goto error; 625238104Sdes 626238104Sdes if (origin) { 627238104Sdes if (!(my_origin = ldns_rdf_clone(origin))) goto error; 628238104Sdes if (!(my_prev = ldns_rdf_clone(origin))) goto error; 629238104Sdes } 630238104Sdes 631238104Sdes#ifdef FASTER_DNSSEC_ZONE_NEW_FRM_FP 632238104Sdes if (ldns_dnssec_zone_add_rr(newzone, ldns_zone_soa(zone)) 633238104Sdes != LDNS_STATUS_OK) goto error; 634238104Sdes 635238104Sdes for (i = 0; i < ldns_rr_list_rr_count(ldns_zone_rrs(zone)); i++) { 636238104Sdes cur_rr = ldns_rr_list_rr(ldns_zone_rrs(zone), i); 637238104Sdes status = LDNS_STATUS_OK; 638238104Sdes#else 639238104Sdes while (!feof(fp)) { 640238104Sdes status = ldns_rr_new_frm_fp_l(&cur_rr, fp, &my_ttl, &my_origin, 641238104Sdes &my_prev, line_nr); 642238104Sdes 643238104Sdes#endif 644238104Sdes switch (status) { 645238104Sdes case LDNS_STATUS_OK: 646238104Sdes 647238104Sdes status = ldns_dnssec_zone_add_rr(newzone, cur_rr); 648238104Sdes if (status == 649238104Sdes LDNS_STATUS_DNSSEC_NSEC3_ORIGINAL_NOT_FOUND) { 650238104Sdes 651238104Sdes if (rr_is_rrsig_covering(cur_rr, 652238104Sdes LDNS_RR_TYPE_NSEC3)){ 653238104Sdes ldns_rr_list_push_rr(todo_nsec3_rrsigs, 654238104Sdes cur_rr); 655238104Sdes } else { 656238104Sdes ldns_rr_list_push_rr(todo_nsec3s, 657238104Sdes cur_rr); 658238104Sdes } 659269257Sdes status = LDNS_STATUS_OK; 660269257Sdes 661238104Sdes } else if (status != LDNS_STATUS_OK) 662238104Sdes goto error; 663238104Sdes 664238104Sdes break; 665238104Sdes 666238104Sdes 667238104Sdes case LDNS_STATUS_SYNTAX_EMPTY: /* empty line was seen */ 668238104Sdes case LDNS_STATUS_SYNTAX_TTL: /* the ttl was set*/ 669238104Sdes case LDNS_STATUS_SYNTAX_ORIGIN: /* the origin was set*/ 670246854Sdes status = LDNS_STATUS_OK; 671238104Sdes break; 672238104Sdes 673238104Sdes case LDNS_STATUS_SYNTAX_INCLUDE:/* $include not implemented */ 674238104Sdes status = LDNS_STATUS_SYNTAX_INCLUDE_ERR_NOTIMPL; 675238104Sdes break; 676238104Sdes 677238104Sdes default: 678238104Sdes goto error; 679238104Sdes } 680238104Sdes } 681238104Sdes 682238104Sdes if (ldns_rr_list_rr_count(todo_nsec3s) > 0) { 683238104Sdes (void) ldns_dnssec_zone_add_empty_nonterminals(newzone); 684269257Sdes for (i = 0; status == LDNS_STATUS_OK && 685246854Sdes i < ldns_rr_list_rr_count(todo_nsec3s); i++) { 686238104Sdes cur_rr = ldns_rr_list_rr(todo_nsec3s, i); 687238104Sdes status = ldns_dnssec_zone_add_rr(newzone, cur_rr); 688238104Sdes } 689269257Sdes } 690269257Sdes if (ldns_rr_list_rr_count(todo_nsec3_rrsigs) > 0) { 691246854Sdes for (i = 0; status == LDNS_STATUS_OK && 692246854Sdes i < ldns_rr_list_rr_count(todo_nsec3_rrsigs); 693246854Sdes i++){ 694238104Sdes cur_rr = ldns_rr_list_rr(todo_nsec3_rrsigs, i); 695238104Sdes status = ldns_dnssec_zone_add_rr(newzone, cur_rr); 696238104Sdes } 697238104Sdes } 698238104Sdes 699238104Sdes if (z) { 700238104Sdes *z = newzone; 701246854Sdes newzone = NULL; 702238104Sdes } else { 703238104Sdes ldns_dnssec_zone_free(newzone); 704238104Sdes } 705238104Sdes 706238104Sdeserror: 707238104Sdes#ifdef FASTER_DNSSEC_ZONE_NEW_FRM_FP 708238104Sdes if (zone) { 709238104Sdes ldns_zone_free(zone); 710238104Sdes } 711238104Sdes#endif 712246854Sdes ldns_rr_list_free(todo_nsec3_rrsigs); 713246854Sdes ldns_rr_list_free(todo_nsec3s); 714246854Sdes 715238104Sdes if (my_origin) { 716238104Sdes ldns_rdf_deep_free(my_origin); 717238104Sdes } 718238104Sdes if (my_prev) { 719238104Sdes ldns_rdf_deep_free(my_prev); 720238104Sdes } 721238104Sdes if (newzone) { 722238104Sdes ldns_dnssec_zone_free(newzone); 723238104Sdes } 724238104Sdes return status; 725238104Sdes} 726238104Sdes 727238104Sdesldns_status 728238104Sdesldns_dnssec_zone_new_frm_fp(ldns_dnssec_zone** z, FILE* fp, ldns_rdf* origin, 729238104Sdes uint32_t ttl, ldns_rr_class ATTR_UNUSED(c)) 730238104Sdes{ 731238104Sdes return ldns_dnssec_zone_new_frm_fp_l(z, fp, origin, ttl, c, NULL); 732238104Sdes} 733238104Sdes 734246827Sdesstatic void 735238104Sdesldns_dnssec_name_node_free(ldns_rbnode_t *node, void *arg) { 736238104Sdes (void) arg; 737238104Sdes ldns_dnssec_name_free((ldns_dnssec_name *)node->data); 738238104Sdes LDNS_FREE(node); 739238104Sdes} 740238104Sdes 741246827Sdesstatic void 742238104Sdesldns_dnssec_name_node_deep_free(ldns_rbnode_t *node, void *arg) { 743238104Sdes (void) arg; 744238104Sdes ldns_dnssec_name_deep_free((ldns_dnssec_name *)node->data); 745238104Sdes LDNS_FREE(node); 746238104Sdes} 747238104Sdes 748238104Sdesvoid 749238104Sdesldns_dnssec_zone_free(ldns_dnssec_zone *zone) 750238104Sdes{ 751238104Sdes if (zone) { 752238104Sdes if (zone->names) { 753238104Sdes /* destroy all name structures within the tree */ 754238104Sdes ldns_traverse_postorder(zone->names, 755238104Sdes ldns_dnssec_name_node_free, 756238104Sdes NULL); 757238104Sdes LDNS_FREE(zone->names); 758238104Sdes } 759238104Sdes LDNS_FREE(zone); 760238104Sdes } 761238104Sdes} 762238104Sdes 763238104Sdesvoid 764238104Sdesldns_dnssec_zone_deep_free(ldns_dnssec_zone *zone) 765238104Sdes{ 766238104Sdes if (zone) { 767238104Sdes if (zone->names) { 768238104Sdes /* destroy all name structures within the tree */ 769238104Sdes ldns_traverse_postorder(zone->names, 770238104Sdes ldns_dnssec_name_node_deep_free, 771238104Sdes NULL); 772238104Sdes LDNS_FREE(zone->names); 773238104Sdes } 774238104Sdes LDNS_FREE(zone); 775238104Sdes } 776238104Sdes} 777238104Sdes 778238104Sdes/* use for dname comparison in tree */ 779249307Sdesint 780238104Sdesldns_dname_compare_v(const void *a, const void *b) { 781238104Sdes return ldns_dname_compare((ldns_rdf *)a, (ldns_rdf *)b); 782238104Sdes} 783238104Sdes 784269257Sdesstatic void 785269257Sdesldns_dnssec_name_make_hashed_name(ldns_dnssec_zone *zone, 786269257Sdes ldns_dnssec_name* name, ldns_rr* nsec3rr); 787238104Sdes 788269257Sdesstatic void 789269257Sdesldns_hashed_names_node_free(ldns_rbnode_t *node, void *arg) { 790269257Sdes (void) arg; 791269257Sdes LDNS_FREE(node); 792269257Sdes} 793238104Sdes 794269257Sdesstatic void 795269257Sdesldns_dnssec_zone_hashed_names_from_nsec3( 796269257Sdes ldns_dnssec_zone* zone, ldns_rr* nsec3rr) 797269257Sdes{ 798269257Sdes ldns_rbnode_t* current_node; 799269257Sdes ldns_dnssec_name* current_name; 800269257Sdes 801269257Sdes assert(zone != NULL); 802269257Sdes assert(nsec3rr != NULL); 803269257Sdes 804269257Sdes if (zone->hashed_names) { 805269257Sdes ldns_traverse_postorder(zone->hashed_names, 806269257Sdes ldns_hashed_names_node_free, NULL); 807269257Sdes LDNS_FREE(zone->hashed_names); 808269257Sdes } 809269257Sdes zone->_nsec3params = nsec3rr; 810269257Sdes 811269257Sdes /* So this is a NSEC3 zone. 812269257Sdes * Calculate hashes for all names already in the zone 813269257Sdes */ 814269257Sdes zone->hashed_names = ldns_rbtree_create(ldns_dname_compare_v); 815269257Sdes if (zone->hashed_names == NULL) { 816269257Sdes return; 817269257Sdes } 818269257Sdes for ( current_node = ldns_rbtree_first(zone->names) 819269257Sdes ; current_node != LDNS_RBTREE_NULL 820269257Sdes ; current_node = ldns_rbtree_next(current_node) 821269257Sdes ) { 822238104Sdes current_name = (ldns_dnssec_name *) current_node->data; 823269257Sdes ldns_dnssec_name_make_hashed_name(zone, current_name, nsec3rr); 824269257Sdes 825269257Sdes } 826269257Sdes} 827269257Sdes 828269257Sdesstatic void 829269257Sdesldns_dnssec_name_make_hashed_name(ldns_dnssec_zone *zone, 830269257Sdes ldns_dnssec_name* name, ldns_rr* nsec3rr) 831269257Sdes{ 832269257Sdes ldns_rbnode_t* new_node; 833269257Sdes 834269257Sdes assert(name != NULL); 835269257Sdes if (! zone->_nsec3params) { 836269257Sdes if (! nsec3rr) { 837269257Sdes return; 838238104Sdes } 839269257Sdes ldns_dnssec_zone_hashed_names_from_nsec3(zone, nsec3rr); 840269257Sdes 841269257Sdes } else if (! nsec3rr) { 842269257Sdes nsec3rr = zone->_nsec3params; 843269257Sdes } 844269257Sdes name->hashed_name = ldns_nsec3_hash_name_frm_nsec3(nsec3rr, name->name); 845269257Sdes 846269257Sdes /* Also store in zone->hashed_names */ 847269257Sdes if ((new_node = LDNS_MALLOC(ldns_rbnode_t))) { 848269257Sdes 849269257Sdes new_node->key = name->hashed_name; 850269257Sdes new_node->data = name; 851269257Sdes 852269257Sdes if (ldns_rbtree_insert(zone->hashed_names, new_node) == NULL) { 853269257Sdes 854269257Sdes LDNS_FREE(new_node); 855238104Sdes } 856238104Sdes } 857238104Sdes} 858238104Sdes 859269257Sdes 860269257Sdesstatic ldns_rbnode_t * 861269257Sdesldns_dnssec_zone_find_nsec3_original(ldns_dnssec_zone *zone, ldns_rr *rr) { 862269257Sdes ldns_rdf *hashed_name; 863269257Sdes 864269257Sdes hashed_name = ldns_dname_label(ldns_rr_owner(rr), 0); 865269257Sdes if (hashed_name == NULL) { 866269257Sdes return NULL; 867269257Sdes } 868269257Sdes if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_NSEC3 && ! zone->_nsec3params){ 869269257Sdes 870269257Sdes ldns_dnssec_zone_hashed_names_from_nsec3(zone, rr); 871269257Sdes } 872269257Sdes if (zone->hashed_names == NULL) { 873269257Sdes ldns_rdf_deep_free(hashed_name); 874269257Sdes return NULL; 875269257Sdes } 876269257Sdes return ldns_rbtree_search(zone->hashed_names, hashed_name); 877269257Sdes} 878269257Sdes 879238104Sdesldns_status 880238104Sdesldns_dnssec_zone_add_rr(ldns_dnssec_zone *zone, ldns_rr *rr) 881238104Sdes{ 882238104Sdes ldns_status result = LDNS_STATUS_OK; 883238104Sdes ldns_dnssec_name *cur_name; 884238104Sdes ldns_rbnode_t *cur_node; 885238104Sdes ldns_rr_type type_covered = 0; 886238104Sdes 887238104Sdes if (!zone || !rr) { 888238104Sdes return LDNS_STATUS_ERR; 889238104Sdes } 890238104Sdes 891238104Sdes if (!zone->names) { 892238104Sdes zone->names = ldns_rbtree_create(ldns_dname_compare_v); 893238104Sdes if(!zone->names) return LDNS_STATUS_MEM_ERR; 894238104Sdes } 895238104Sdes 896238104Sdes /* we need the original of the hashed name if this is 897238104Sdes an NSEC3, or an RRSIG that covers an NSEC3 */ 898238104Sdes if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_RRSIG) { 899238104Sdes type_covered = ldns_rdf2rr_type(ldns_rr_rrsig_typecovered(rr)); 900238104Sdes } 901238104Sdes if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_NSEC3 || 902238104Sdes type_covered == LDNS_RR_TYPE_NSEC3) { 903269257Sdes cur_node = ldns_dnssec_zone_find_nsec3_original(zone, rr); 904238104Sdes if (!cur_node) { 905238104Sdes return LDNS_STATUS_DNSSEC_NSEC3_ORIGINAL_NOT_FOUND; 906238104Sdes } 907238104Sdes } else { 908238104Sdes cur_node = ldns_rbtree_search(zone->names, ldns_rr_owner(rr)); 909238104Sdes } 910238104Sdes if (!cur_node) { 911238104Sdes /* add */ 912238104Sdes cur_name = ldns_dnssec_name_new_frm_rr(rr); 913238104Sdes if(!cur_name) return LDNS_STATUS_MEM_ERR; 914238104Sdes cur_node = LDNS_MALLOC(ldns_rbnode_t); 915238104Sdes if(!cur_node) { 916238104Sdes ldns_dnssec_name_free(cur_name); 917238104Sdes return LDNS_STATUS_MEM_ERR; 918238104Sdes } 919238104Sdes cur_node->key = ldns_rr_owner(rr); 920238104Sdes cur_node->data = cur_name; 921238104Sdes (void)ldns_rbtree_insert(zone->names, cur_node); 922269257Sdes ldns_dnssec_name_make_hashed_name(zone, cur_name, NULL); 923238104Sdes } else { 924238104Sdes cur_name = (ldns_dnssec_name *) cur_node->data; 925238104Sdes result = ldns_dnssec_name_add_rr(cur_name, rr); 926238104Sdes } 927238104Sdes if (ldns_rr_get_type(rr) == LDNS_RR_TYPE_SOA) { 928238104Sdes zone->soa = cur_name; 929238104Sdes } 930238104Sdes return result; 931238104Sdes} 932238104Sdes 933238104Sdesvoid 934238104Sdesldns_dnssec_zone_names_print_fmt(FILE *out, const ldns_output_format *fmt, 935238104Sdes ldns_rbtree_t *tree, 936238104Sdes bool print_soa) 937238104Sdes{ 938238104Sdes ldns_rbnode_t *node; 939238104Sdes ldns_dnssec_name *name; 940238104Sdes 941238104Sdes node = ldns_rbtree_first(tree); 942238104Sdes while (node != LDNS_RBTREE_NULL) { 943238104Sdes name = (ldns_dnssec_name *) node->data; 944238104Sdes ldns_dnssec_name_print_soa_fmt(out, fmt, name, print_soa); 945238104Sdes if ((fmt->flags & LDNS_COMMENT_LAYOUT)) 946238104Sdes fprintf(out, ";\n"); 947238104Sdes node = ldns_rbtree_next(node); 948238104Sdes } 949238104Sdes} 950238104Sdes 951238104Sdesvoid 952238104Sdesldns_dnssec_zone_names_print(FILE *out, ldns_rbtree_t *tree, bool print_soa) 953238104Sdes{ 954238104Sdes ldns_dnssec_zone_names_print_fmt(out, ldns_output_format_default, 955238104Sdes tree, print_soa); 956238104Sdes} 957238104Sdes 958238104Sdesvoid 959238104Sdesldns_dnssec_zone_print_fmt(FILE *out, const ldns_output_format *fmt, 960238104Sdes ldns_dnssec_zone *zone) 961238104Sdes{ 962238104Sdes if (zone) { 963238104Sdes if (zone->soa) { 964238104Sdes if ((fmt->flags & LDNS_COMMENT_LAYOUT)) { 965238104Sdes fprintf(out, ";; Zone: "); 966238104Sdes ldns_rdf_print(out, ldns_dnssec_name_name( 967238104Sdes zone->soa)); 968238104Sdes fprintf(out, "\n;\n"); 969238104Sdes } 970238104Sdes ldns_dnssec_rrsets_print_fmt(out, fmt, 971238104Sdes ldns_dnssec_name_find_rrset( 972238104Sdes zone->soa, 973238104Sdes LDNS_RR_TYPE_SOA), 974238104Sdes false); 975238104Sdes if ((fmt->flags & LDNS_COMMENT_LAYOUT)) 976238104Sdes fprintf(out, ";\n"); 977238104Sdes } 978238104Sdes 979238104Sdes if (zone->names) { 980238104Sdes ldns_dnssec_zone_names_print_fmt(out, fmt, 981238104Sdes zone->names, false); 982238104Sdes } 983238104Sdes } 984238104Sdes} 985238104Sdes 986238104Sdesvoid 987238104Sdesldns_dnssec_zone_print(FILE *out, ldns_dnssec_zone *zone) 988238104Sdes{ 989238104Sdes ldns_dnssec_zone_print_fmt(out, ldns_output_format_default, zone); 990238104Sdes} 991238104Sdes 992238104Sdesldns_status 993238104Sdesldns_dnssec_zone_add_empty_nonterminals(ldns_dnssec_zone *zone) 994238104Sdes{ 995238104Sdes ldns_dnssec_name *new_name; 996238104Sdes ldns_rdf *cur_name; 997238104Sdes ldns_rdf *next_name; 998238104Sdes ldns_rbnode_t *cur_node, *next_node, *new_node; 999238104Sdes 1000238104Sdes /* for the detection */ 1001238104Sdes uint16_t i, cur_label_count, next_label_count; 1002238104Sdes uint16_t soa_label_count = 0; 1003238104Sdes ldns_rdf *l1, *l2; 1004238104Sdes int lpos; 1005238104Sdes 1006238104Sdes if (!zone) { 1007238104Sdes return LDNS_STATUS_ERR; 1008238104Sdes } 1009238104Sdes if (zone->soa && zone->soa->name) { 1010238104Sdes soa_label_count = ldns_dname_label_count(zone->soa->name); 1011238104Sdes } 1012238104Sdes 1013238104Sdes cur_node = ldns_rbtree_first(zone->names); 1014238104Sdes while (cur_node != LDNS_RBTREE_NULL) { 1015238104Sdes next_node = ldns_rbtree_next(cur_node); 1016238104Sdes 1017238104Sdes /* skip glue */ 1018238104Sdes while (next_node != LDNS_RBTREE_NULL && 1019238104Sdes next_node->data && 1020238104Sdes ((ldns_dnssec_name *)next_node->data)->is_glue 1021238104Sdes ) { 1022238104Sdes next_node = ldns_rbtree_next(next_node); 1023238104Sdes } 1024238104Sdes 1025238104Sdes if (next_node == LDNS_RBTREE_NULL) { 1026238104Sdes next_node = ldns_rbtree_first(zone->names); 1027238104Sdes } 1028246854Sdes if (! cur_node->data || ! next_node->data) { 1029246854Sdes return LDNS_STATUS_ERR; 1030246854Sdes } 1031238104Sdes cur_name = ((ldns_dnssec_name *)cur_node->data)->name; 1032238104Sdes next_name = ((ldns_dnssec_name *)next_node->data)->name; 1033238104Sdes cur_label_count = ldns_dname_label_count(cur_name); 1034238104Sdes next_label_count = ldns_dname_label_count(next_name); 1035238104Sdes 1036238104Sdes /* Since the names are in canonical order, we can 1037238104Sdes * recognize empty non-terminals by their labels; 1038238104Sdes * every label after the first one on the next owner 1039238104Sdes * name is a non-terminal if it either does not exist 1040238104Sdes * in the current name or is different from the same 1041238104Sdes * label in the current name (counting from the end) 1042238104Sdes */ 1043238104Sdes for (i = 1; i < next_label_count - soa_label_count; i++) { 1044238104Sdes lpos = (int)cur_label_count - (int)next_label_count + (int)i; 1045238104Sdes if (lpos >= 0) { 1046238104Sdes l1 = ldns_dname_clone_from(cur_name, (uint8_t)lpos); 1047238104Sdes } else { 1048238104Sdes l1 = NULL; 1049238104Sdes } 1050238104Sdes l2 = ldns_dname_clone_from(next_name, i); 1051238104Sdes 1052238104Sdes if (!l1 || ldns_dname_compare(l1, l2) != 0) { 1053238104Sdes /* We have an empty nonterminal, add it to the 1054238104Sdes * tree 1055238104Sdes */ 1056238104Sdes new_name = ldns_dnssec_name_new(); 1057238104Sdes if (!new_name) { 1058238104Sdes return LDNS_STATUS_MEM_ERR; 1059238104Sdes } 1060238104Sdes new_name->name = ldns_dname_clone_from(next_name, 1061238104Sdes i); 1062238104Sdes if (!new_name->name) { 1063238104Sdes ldns_dnssec_name_free(new_name); 1064238104Sdes return LDNS_STATUS_MEM_ERR; 1065238104Sdes } 1066238104Sdes new_name->name_alloced = true; 1067238104Sdes new_node = LDNS_MALLOC(ldns_rbnode_t); 1068238104Sdes if (!new_node) { 1069238104Sdes ldns_dnssec_name_free(new_name); 1070238104Sdes return LDNS_STATUS_MEM_ERR; 1071238104Sdes } 1072238104Sdes new_node->key = new_name->name; 1073238104Sdes new_node->data = new_name; 1074238104Sdes (void)ldns_rbtree_insert(zone->names, new_node); 1075269257Sdes ldns_dnssec_name_make_hashed_name( 1076269257Sdes zone, new_name, NULL); 1077238104Sdes } 1078238104Sdes ldns_rdf_deep_free(l1); 1079238104Sdes ldns_rdf_deep_free(l2); 1080238104Sdes } 1081238104Sdes 1082238104Sdes /* we might have inserted a new node after 1083238104Sdes * the current one so we can't just use next() 1084238104Sdes */ 1085238104Sdes if (next_node != ldns_rbtree_first(zone->names)) { 1086238104Sdes cur_node = next_node; 1087238104Sdes } else { 1088238104Sdes cur_node = LDNS_RBTREE_NULL; 1089238104Sdes } 1090238104Sdes } 1091238104Sdes return LDNS_STATUS_OK; 1092238104Sdes} 1093238104Sdes 1094238104Sdesbool 1095238104Sdesldns_dnssec_zone_is_nsec3_optout(ldns_dnssec_zone* zone) 1096238104Sdes{ 1097238104Sdes ldns_rr* nsec3; 1098238104Sdes ldns_rbnode_t* node; 1099238104Sdes 1100238104Sdes if (ldns_dnssec_name_find_rrset(zone->soa, LDNS_RR_TYPE_NSEC3PARAM)) { 1101238104Sdes node = ldns_rbtree_first(zone->names); 1102238104Sdes while (node != LDNS_RBTREE_NULL) { 1103238104Sdes nsec3 = ((ldns_dnssec_name*)node->data)->nsec; 1104238104Sdes if (nsec3 &&ldns_rr_get_type(nsec3) 1105238104Sdes == LDNS_RR_TYPE_NSEC3 && 1106238104Sdes ldns_nsec3_optout(nsec3)) { 1107238104Sdes return true; 1108238104Sdes } 1109238104Sdes node = ldns_rbtree_next(node); 1110238104Sdes } 1111238104Sdes } 1112238104Sdes return false; 1113238104Sdes} 1114