1 /* 2 * special zone file structures and functions for better dnssec handling 3 * 4 * A zone contains a SOA dnssec_zone_rrset, and an AVL tree of 'normal' 5 * dnssec_zone_rrsets, indexed by name and type 6 */ 7 8 #ifndef LDNS_DNSSEC_ZONE_H 9 #define LDNS_DNSSEC_ZONE_H 10 11 #include <ldns/rbtree.h> 12 #include <ldns/host2str.h> 13 14 #ifdef __cplusplus 15 extern "C" { 16 #endif 17 18 /** 19 * Singly linked list of rrs 20 */ 21 typedef struct ldns_struct_dnssec_rrs ldns_dnssec_rrs; 22 struct ldns_struct_dnssec_rrs 23 { 24 ldns_rr *rr; 25 ldns_dnssec_rrs *next; 26 }; 27 28 /** 29 * Singly linked list of RRsets 30 */ 31 typedef struct ldns_struct_dnssec_rrsets ldns_dnssec_rrsets; 32 struct ldns_struct_dnssec_rrsets 33 { 34 ldns_dnssec_rrs *rrs; 35 ldns_rr_type type; 36 ldns_dnssec_rrs *signatures; 37 ldns_dnssec_rrsets *next; 38 }; 39 40 /** 41 * Structure containing all resource records for a domain name 42 * Including the derived NSEC3, if present 43 */ 44 typedef struct ldns_struct_dnssec_name ldns_dnssec_name; 45 struct ldns_struct_dnssec_name 46 { 47 /** 48 * pointer to a dname containing the name. 49 * Usually points to the owner name of the first RR of the first RRset 50 */ 51 ldns_rdf *name; 52 /** 53 * Usually, the name is a pointer to the owner name of the first rr for 54 * this name, but sometimes there is no actual data to point to, 55 * for instance in 56 * names representing empty nonterminals. If so, set name_alloced to true to 57 * indicate that this data must also be freed when the name is freed 58 */ 59 bool name_alloced; 60 /** 61 * The rrsets for this name 62 */ 63 ldns_dnssec_rrsets *rrsets; 64 /** 65 * NSEC pointing to the next name (or NSEC3 pointing to the next NSEC3) 66 */ 67 ldns_rr *nsec; 68 /** 69 * signatures for the NSEC record 70 */ 71 ldns_dnssec_rrs *nsec_signatures; 72 /** 73 * Unlike what the name is_glue suggests, this field is set to true by 74 * ldns_dnssec_zone_mark_glue() or ldns_dnssec_zone_mark_and_get_glue() 75 * when the name, this dnssec_name struct represents, is occluded. 76 * Names that contain other occluded rrsets and records with glue on 77 * the delegation point will NOT have this bool set to true. 78 * This field should NOT be read directly, but only via the 79 * ldns_dnssec_name_is_glue() function! 80 */ 81 bool is_glue; 82 /** 83 * pointer to store the hashed name (only used when in an NSEC3 zone 84 */ 85 ldns_rdf *hashed_name; 86 }; 87 88 /** 89 * Structure containing a dnssec zone 90 */ 91 struct ldns_struct_dnssec_zone { 92 /** points to the name containing the SOA RR */ 93 ldns_dnssec_name *soa; 94 /** tree of ldns_dnssec_names */ 95 ldns_rbtree_t *names; 96 /** tree of ldns_dnssec_names by nsec3 hashes (when applicable) */ 97 ldns_rbtree_t *hashed_names; 98 /** points to the first added NSEC3 rr whose parameters will be 99 * assumed for all subsequent NSEC3 rr's and which will be used 100 * to calculate hashed names 101 */ 102 ldns_rr *_nsec3params; 103 }; 104 typedef struct ldns_struct_dnssec_zone ldns_dnssec_zone; 105 106 /** 107 * Creates a new entry for 1 pointer to an rr and 1 pointer to the next rrs 108 * \return the allocated data 109 */ 110 ldns_dnssec_rrs *ldns_dnssec_rrs_new(void); 111 112 /** 113 * Frees the list of rrs, but *not* the individual ldns_rr records 114 * contained in the list 115 * 116 * \param[in] rrs the data structure to free 117 */ 118 void ldns_dnssec_rrs_free(ldns_dnssec_rrs *rrs); 119 120 /** 121 * Frees the list of rrs, and the individual ldns_rr records 122 * contained in the list 123 * 124 * \param[in] rrs the data structure to free 125 */ 126 void ldns_dnssec_rrs_deep_free(ldns_dnssec_rrs *rrs); 127 128 /** 129 * Adds an RR to the list of RRs. The list will remain ordered. 130 * If an equal RR already exists, this RR will not be added. 131 * 132 * \param[in] rrs the list to add to 133 * \param[in] rr the RR to add 134 * \return LDNS_STATUS_OK on success and LDNS_STATUS_EQUAL_ERR when and 135 * RR with equal ownername, class, type and rdata already exists. 136 */ 137 ldns_status ldns_dnssec_rrs_add_rr(ldns_dnssec_rrs *rrs, ldns_rr *rr); 138 139 /** 140 * Prints the given rrs to the file descriptor 141 * 142 * \param[in] out the file descriptor to print to 143 * \param[in] rrs the list of RRs to print 144 */ 145 void ldns_dnssec_rrs_print(FILE *out, const ldns_dnssec_rrs *rrs); 146 147 /** 148 * Prints the given rrs to the file descriptor 149 * 150 * \param[in] out the file descriptor to print to 151 * \param[in] fmt the format of the textual representation 152 * \param[in] rrs the list of RRs to print 153 */ 154 void ldns_dnssec_rrs_print_fmt(FILE *out, 155 const ldns_output_format *fmt, const ldns_dnssec_rrs *rrs); 156 157 /** 158 * Creates a new list (entry) of RRsets 159 * \return the newly allocated structure 160 */ 161 ldns_dnssec_rrsets *ldns_dnssec_rrsets_new(void); 162 163 /** 164 * Frees the list of rrsets and their rrs, but *not* the ldns_rr 165 * records in the sets 166 * 167 * \param[in] rrsets the data structure to free 168 */ 169 void ldns_dnssec_rrsets_free(ldns_dnssec_rrsets *rrsets); 170 171 /** 172 * Frees the list of rrsets and their rrs, and the ldns_rr 173 * records in the sets 174 * 175 * \param[in] rrsets the data structure to free 176 */ 177 void ldns_dnssec_rrsets_deep_free(ldns_dnssec_rrsets *rrsets); 178 179 /** 180 * Returns the rr type of the rrset (that is head of the given list) 181 * 182 * \param[in] rrsets the rrset to get the type of 183 * \return the rr type 184 */ 185 ldns_rr_type ldns_dnssec_rrsets_type(const ldns_dnssec_rrsets *rrsets); 186 187 /** 188 * Sets the RR type of the rrset (that is head of the given list) 189 * 190 * \param[in] rrsets the rrset to set the type of 191 * \param[in] type the type to set 192 * \return LDNS_STATUS_OK on success 193 */ 194 ldns_status ldns_dnssec_rrsets_set_type(ldns_dnssec_rrsets *rrsets, 195 ldns_rr_type type); 196 197 /** 198 * Add an ldns_rr to the corresponding RRset in the given list of RRsets. 199 * If it is not present, add it as a new RRset with 1 record. 200 * 201 * \param[in] rrsets the list of rrsets to add the RR to 202 * \param[in] rr the rr to add to the list of rrsets 203 * \return LDNS_STATUS_OK on success and LDNS_STATUS_EQUAL_ERR when and 204 * RR with equal ownername, class, type and rdata already exists. 205 */ 206 ldns_status ldns_dnssec_rrsets_add_rr(ldns_dnssec_rrsets *rrsets, ldns_rr *rr); 207 208 /** 209 * Print the given list of rrsets to the given file descriptor 210 * 211 * \param[in] out the file descriptor to print to 212 * \param[in] rrsets the list of RRsets to print 213 * \param[in] follow if set to false, only print the first RRset 214 */ 215 void ldns_dnssec_rrsets_print(FILE *out, 216 const ldns_dnssec_rrsets *rrsets, 217 bool follow); 218 219 /** 220 * Print the given list of rrsets to the given file descriptor 221 * 222 * \param[in] out the file descriptor to print to 223 * \param[in] fmt the format of the textual representation 224 * \param[in] rrsets the list of RRsets to print 225 * \param[in] follow if set to false, only print the first RRset 226 */ 227 void ldns_dnssec_rrsets_print_fmt(FILE *out, 228 const ldns_output_format *fmt, 229 const ldns_dnssec_rrsets *rrsets, 230 bool follow); 231 232 233 /** 234 * Create a new data structure for a dnssec name 235 * \return the allocated structure 236 */ 237 ldns_dnssec_name *ldns_dnssec_name_new(void); 238 239 /** 240 * Create a new data structure for a dnssec name for the given RR 241 * 242 * \param[in] rr the RR to derive properties from, and to add to the name 243 */ 244 ldns_dnssec_name *ldns_dnssec_name_new_frm_rr(ldns_rr *rr); 245 246 /** 247 * Frees the name structure and its rrs and rrsets. 248 * Individual ldns_rr records therein are not freed 249 * 250 * \param[in] name the structure to free 251 */ 252 void ldns_dnssec_name_free(ldns_dnssec_name *name); 253 254 /** 255 * Frees the name structure and its rrs and rrsets. 256 * Individual ldns_rr records contained in the name are also freed 257 * 258 * \param[in] name the structure to free 259 */ 260 void ldns_dnssec_name_deep_free(ldns_dnssec_name *name); 261 262 /** 263 * Returns the domain name of the given dnssec_name structure 264 * 265 * \param[in] name the dnssec name to get the domain name from 266 * \return the domain name 267 */ 268 ldns_rdf *ldns_dnssec_name_name(const ldns_dnssec_name *name); 269 270 271 /** 272 * Sets the domain name of the given dnssec_name structure 273 * 274 * \param[in] name the dnssec name to set the domain name of 275 * \param[in] dname the domain name to set it to. This data is *not* copied. 276 */ 277 void ldns_dnssec_name_set_name(ldns_dnssec_name *name, 278 ldns_rdf *dname); 279 /** 280 * Returns if dnssec_name structure is marked as glue. 281 * The ldns_dnssec_zone_mark_glue() function has to be called on a zone before 282 * using this function. 283 * Only names that have only glue rrsets will be marked. 284 * Names that have other occluded rrsets and names containing glue on the 285 * delegation point will NOT be marked! 286 * 287 * \param[in] name the dnssec name to get the domain name from 288 * \return true if the structure is marked as glue, false otherwise. 289 */ 290 bool ldns_dnssec_name_is_glue(const ldns_dnssec_name *name); 291 292 /** 293 * Sets the NSEC(3) RR of the given dnssec_name structure 294 * 295 * \param[in] name the dnssec name to set the domain name of 296 * \param[in] nsec the nsec rr to set it to. This data is *not* copied. 297 */ 298 void ldns_dnssec_name_set_nsec(ldns_dnssec_name *name, ldns_rr *nsec); 299 300 /** 301 * Compares the domain names of the two arguments in their 302 * canonical ordering. 303 * 304 * \param[in] a The first dnssec_name to compare 305 * \param[in] b The second dnssec_name to compare 306 * \return -1 if the domain name of a comes before that of b in canonical 307 * ordering, 1 if it is the other way around, and 0 if they are 308 * equal 309 */ 310 int ldns_dnssec_name_cmp(const void *a, const void *b); 311 312 /** 313 * Inserts the given rr at the right place in the current dnssec_name 314 * No checking is done whether the name matches 315 * 316 * \param[in] name The ldns_dnssec_name to add the RR to 317 * \param[in] rr The RR to add 318 * \return LDNS_STATUS_OK on success and LDNS_STATUS_EQUAL_ERR when and 319 * RR with equal ownername, class, type and rdata already exists, 320 * and an error code otherwise 321 */ 322 ldns_status ldns_dnssec_name_add_rr(ldns_dnssec_name *name, 323 ldns_rr *rr); 324 325 /** 326 * Find the RRset with the given type in within this name structure 327 * 328 * \param[in] name the name to find the RRset in 329 * \param[in] type the type of the RRset to find 330 * \return the RRset, or NULL if not present 331 */ 332 ldns_dnssec_rrsets *ldns_dnssec_name_find_rrset(const ldns_dnssec_name *name, 333 ldns_rr_type type); 334 335 /** 336 * Find the RRset with the given name and type in the zone 337 * 338 * \param[in] zone the zone structure to find the RRset in 339 * \param[in] dname the domain name of the RRset to find 340 * \param[in] type the type of the RRset to find 341 * \return the RRset, or NULL if not present 342 */ 343 ldns_dnssec_rrsets *ldns_dnssec_zone_find_rrset(const ldns_dnssec_zone *zone, 344 const ldns_rdf *dname, 345 ldns_rr_type type); 346 347 /** 348 * Prints the RRs in the dnssec name structure to the given 349 * file descriptor 350 * 351 * \param[in] out the file descriptor to print to 352 * \param[in] name the name structure to print the contents of 353 */ 354 void ldns_dnssec_name_print(FILE *out, const ldns_dnssec_name *name); 355 356 /** 357 * Prints the RRs in the dnssec name structure to the given 358 * file descriptor 359 * 360 * \param[in] out the file descriptor to print to 361 * \param[in] fmt the format of the textual representation 362 * \param[in] name the name structure to print the contents of 363 */ 364 void ldns_dnssec_name_print_fmt(FILE *out, 365 const ldns_output_format *fmt, const ldns_dnssec_name *name); 366 367 /** 368 * Creates a new dnssec_zone structure 369 * \return the allocated structure 370 */ 371 ldns_dnssec_zone *ldns_dnssec_zone_new(void); 372 373 /** 374 * Create a new dnssec zone from a file. 375 * \param[out] z the new zone 376 * \param[in] *fp the filepointer to use 377 * \param[in] *origin the zones' origin 378 * \param[in] c default class to use (IN) 379 * \param[in] ttl default ttl to use 380 * 381 * \return ldns_status mesg with an error or LDNS_STATUS_OK 382 */ 383 ldns_status ldns_dnssec_zone_new_frm_fp(ldns_dnssec_zone** z, FILE* fp, 384 const ldns_rdf* origin, uint32_t ttl, ldns_rr_class c); 385 386 /** 387 * Create a new dnssec zone from a file, keep track of the line numbering 388 * \param[out] z the new zone 389 * \param[in] *fp the filepointer to use 390 * \param[in] *origin the zones' origin 391 * \param[in] ttl default ttl to use 392 * \param[in] c default class to use (IN) 393 * \param[out] line_nr used for error msg, to get to the line number 394 * 395 * \return ldns_status mesg with an error or LDNS_STATUS_OK 396 */ 397 ldns_status ldns_dnssec_zone_new_frm_fp_l(ldns_dnssec_zone** z, FILE* fp, 398 const ldns_rdf* origin, uint32_t ttl, ldns_rr_class c, int* line_nr); 399 400 /** 401 * Frees the given zone structure, and its rbtree of dnssec_names 402 * Individual ldns_rr RRs within those names are *not* freed 403 * \param[in] *zone the zone to free 404 */ 405 void ldns_dnssec_zone_free(ldns_dnssec_zone *zone); 406 407 /** 408 * Frees the given zone structure, and its rbtree of dnssec_names 409 * Individual ldns_rr RRs within those names are also freed 410 * \param[in] *zone the zone to free 411 */ 412 void ldns_dnssec_zone_deep_free(ldns_dnssec_zone *zone); 413 414 /** 415 * Adds the given RR to the zone. 416 * It find whether there is a dnssec_name with that name present. 417 * If so, add it to that, if not create a new one. 418 * Special handling of NSEC and RRSIG provided 419 * 420 * \param[in] zone the zone to add the RR to 421 * \param[in] rr The RR to add 422 * \return LDNS_STATUS_OK on success and LDNS_STATUS_EQUAL_ERR when and 423 * RR with equal ownername, class, type and rdata already exists, 424 * and an error code otherwise 425 */ 426 ldns_status ldns_dnssec_zone_add_rr(ldns_dnssec_zone *zone, 427 ldns_rr *rr); 428 429 /** 430 * Prints the rbtree of ldns_dnssec_name structures to the file descriptor 431 * 432 * \param[in] out the file descriptor to print the names to 433 * \param[in] tree the tree of ldns_dnssec_name structures to print 434 * \param[in] print_soa if true, print SOA records, if false, skip them 435 */ 436 void ldns_dnssec_zone_names_print(FILE *out, const ldns_rbtree_t *tree, bool print_soa); 437 438 /** 439 * Prints the rbtree of ldns_dnssec_name structures to the file descriptor 440 * 441 * \param[in] out the file descriptor to print the names to 442 * \param[in] fmt the format of the textual representation 443 * \param[in] tree the tree of ldns_dnssec_name structures to print 444 * \param[in] print_soa if true, print SOA records, if false, skip them 445 */ 446 void ldns_dnssec_zone_names_print_fmt(FILE *out, const ldns_output_format *fmt, 447 const ldns_rbtree_t *tree, bool print_soa); 448 449 /** 450 * Prints the complete zone to the given file descriptor 451 * 452 * \param[in] out the file descriptor to print to 453 * \param[in] zone the dnssec_zone to print 454 */ 455 void ldns_dnssec_zone_print(FILE *out, const ldns_dnssec_zone *zone); 456 457 /** 458 * Prints the complete zone to the given file descriptor 459 * 460 * \param[in] out the file descriptor to print to 461 * \param[in] fmt the format of the textual representation 462 * \param[in] zone the dnssec_zone to print 463 */ 464 void ldns_dnssec_zone_print_fmt(FILE *out, 465 const ldns_output_format *fmt, const ldns_dnssec_zone *zone); 466 467 /** 468 * Adds explicit dnssec_name structures for the empty nonterminals 469 * in this zone. (this is needed for NSEC3 generation) 470 * 471 * \param[in] zone the zone to check for empty nonterminals 472 * return LDNS_STATUS_OK on success. 473 */ 474 ldns_status ldns_dnssec_zone_add_empty_nonterminals(ldns_dnssec_zone *zone); 475 476 /** 477 * If a NSEC3PARAM is available in the apex, walks the zone and returns true 478 * on the first optout nsec3. 479 * 480 * \param[in] zone the zone to check for nsec3 optout records 481 * return true when the zone has at least one nsec3 optout record. 482 */ 483 bool ldns_dnssec_zone_is_nsec3_optout(const ldns_dnssec_zone* zone); 484 485 ldns_status ldns_dnssec_zone_verify_zonemd(ldns_dnssec_zone *zone); 486 487 #ifdef __cplusplus 488 } 489 #endif 490 491 #endif 492