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 135 */ 136 ldns_status ldns_dnssec_rrs_add_rr(ldns_dnssec_rrs *rrs, ldns_rr *rr); 137 138 /** 139 * Prints the given rrs to the file descriptor 140 * 141 * \param[in] out the file descriptor to print to 142 * \param[in] rrs the list of RRs to print 143 */ 144 void ldns_dnssec_rrs_print(FILE *out, const ldns_dnssec_rrs *rrs); 145 146 /** 147 * Prints the given rrs to the file descriptor 148 * 149 * \param[in] out the file descriptor to print to 150 * \param[in] fmt the format of the textual representation 151 * \param[in] rrs the list of RRs to print 152 */ 153 void ldns_dnssec_rrs_print_fmt(FILE *out, 154 const ldns_output_format *fmt, const ldns_dnssec_rrs *rrs); 155 156 /** 157 * Creates a new list (entry) of RRsets 158 * \return the newly allocated structure 159 */ 160 ldns_dnssec_rrsets *ldns_dnssec_rrsets_new(void); 161 162 /** 163 * Frees the list of rrsets and their rrs, but *not* the ldns_rr 164 * records in the sets 165 * 166 * \param[in] rrsets the data structure to free 167 */ 168 void ldns_dnssec_rrsets_free(ldns_dnssec_rrsets *rrsets); 169 170 /** 171 * Frees the list of rrsets and their rrs, and the ldns_rr 172 * records in the sets 173 * 174 * \param[in] rrsets the data structure to free 175 */ 176 void ldns_dnssec_rrsets_deep_free(ldns_dnssec_rrsets *rrsets); 177 178 /** 179 * Returns the rr type of the rrset (that is head of the given list) 180 * 181 * \param[in] rrsets the rrset to get the type of 182 * \return the rr type 183 */ 184 ldns_rr_type ldns_dnssec_rrsets_type(const ldns_dnssec_rrsets *rrsets); 185 186 /** 187 * Sets the RR type of the rrset (that is head of the given list) 188 * 189 * \param[in] rrsets the rrset to set the type of 190 * \param[in] type the type to set 191 * \return LDNS_STATUS_OK on success 192 */ 193 ldns_status ldns_dnssec_rrsets_set_type(ldns_dnssec_rrsets *rrsets, 194 ldns_rr_type type); 195 196 /** 197 * Add an ldns_rr to the corresponding RRset in the given list of RRsets. 198 * If it is not present, add it as a new RRset with 1 record. 199 * 200 * \param[in] rrsets the list of rrsets to add the RR to 201 * \param[in] rr the rr to add to the list of rrsets 202 * \return LDNS_STATUS_OK on success 203 */ 204 ldns_status ldns_dnssec_rrsets_add_rr(ldns_dnssec_rrsets *rrsets, ldns_rr *rr); 205 206 /** 207 * Print the given list of rrsets to the given file descriptor 208 * 209 * \param[in] out the file descriptor to print to 210 * \param[in] rrsets the list of RRsets to print 211 * \param[in] follow if set to false, only print the first RRset 212 */ 213 void ldns_dnssec_rrsets_print(FILE *out, 214 const ldns_dnssec_rrsets *rrsets, 215 bool follow); 216 217 /** 218 * Print the given list of rrsets to the given file descriptor 219 * 220 * \param[in] out the file descriptor to print to 221 * \param[in] fmt the format of the textual representation 222 * \param[in] rrsets the list of RRsets to print 223 * \param[in] follow if set to false, only print the first RRset 224 */ 225 void ldns_dnssec_rrsets_print_fmt(FILE *out, 226 const ldns_output_format *fmt, 227 const ldns_dnssec_rrsets *rrsets, 228 bool follow); 229 230 231 /** 232 * Create a new data structure for a dnssec name 233 * \return the allocated structure 234 */ 235 ldns_dnssec_name *ldns_dnssec_name_new(void); 236 237 /** 238 * Create a new data structure for a dnssec name for the given RR 239 * 240 * \param[in] rr the RR to derive properties from, and to add to the name 241 */ 242 ldns_dnssec_name *ldns_dnssec_name_new_frm_rr(ldns_rr *rr); 243 244 /** 245 * Frees the name structure and its rrs and rrsets. 246 * Individual ldns_rr records therein are not freed 247 * 248 * \param[in] name the structure to free 249 */ 250 void ldns_dnssec_name_free(ldns_dnssec_name *name); 251 252 /** 253 * Frees the name structure and its rrs and rrsets. 254 * Individual ldns_rr records contained in the name are also freed 255 * 256 * \param[in] name the structure to free 257 */ 258 void ldns_dnssec_name_deep_free(ldns_dnssec_name *name); 259 260 /** 261 * Returns the domain name of the given dnssec_name structure 262 * 263 * \param[in] name the dnssec name to get the domain name from 264 * \return the domain name 265 */ 266 ldns_rdf *ldns_dnssec_name_name(const ldns_dnssec_name *name); 267 268 269 /** 270 * Sets the domain name of the given dnssec_name structure 271 * 272 * \param[in] name the dnssec name to set the domain name of 273 * \param[in] dname the domain name to set it to. This data is *not* copied. 274 */ 275 void ldns_dnssec_name_set_name(ldns_dnssec_name *name, 276 ldns_rdf *dname); 277 /** 278 * Returns if dnssec_name structure is marked as glue. 279 * The ldns_dnssec_zone_mark_glue() function has to be called on a zone before 280 * using this function. 281 * Only names that have only glue rrsets will be marked. 282 * Names that have other occluded rrsets and names containing glue on the 283 * delegation point will NOT be marked! 284 * 285 * \param[in] name the dnssec name to get the domain name from 286 * \return true if the structure is marked as glue, false otherwise. 287 */ 288 bool ldns_dnssec_name_is_glue(const ldns_dnssec_name *name); 289 290 /** 291 * Sets the NSEC(3) RR of the given dnssec_name structure 292 * 293 * \param[in] name the dnssec name to set the domain name of 294 * \param[in] nsec the nsec rr to set it to. This data is *not* copied. 295 */ 296 void ldns_dnssec_name_set_nsec(ldns_dnssec_name *name, ldns_rr *nsec); 297 298 /** 299 * Compares the domain names of the two arguments in their 300 * canonical ordering. 301 * 302 * \param[in] a The first dnssec_name to compare 303 * \param[in] b The second dnssec_name to compare 304 * \return -1 if the domain name of a comes before that of b in canonical 305 * ordering, 1 if it is the other way around, and 0 if they are 306 * equal 307 */ 308 int ldns_dnssec_name_cmp(const void *a, const void *b); 309 310 /** 311 * Inserts the given rr at the right place in the current dnssec_name 312 * No checking is done whether the name matches 313 * 314 * \param[in] name The ldns_dnssec_name to add the RR to 315 * \param[in] rr The RR to add 316 * \return LDNS_STATUS_OK on success, error code otherwise 317 */ 318 ldns_status ldns_dnssec_name_add_rr(ldns_dnssec_name *name, 319 ldns_rr *rr); 320 321 /** 322 * Find the RRset with the given type in within this name structure 323 * 324 * \param[in] name the name to find the RRset in 325 * \param[in] type the type of the RRset to find 326 * \return the RRset, or NULL if not present 327 */ 328 ldns_dnssec_rrsets *ldns_dnssec_name_find_rrset(const ldns_dnssec_name *name, 329 ldns_rr_type type); 330 331 /** 332 * Find the RRset with the given name and type in the zone 333 * 334 * \param[in] zone the zone structure to find the RRset in 335 * \param[in] dname the domain name of the RRset to find 336 * \param[in] type the type of the RRset to find 337 * \return the RRset, or NULL if not present 338 */ 339 ldns_dnssec_rrsets *ldns_dnssec_zone_find_rrset(const ldns_dnssec_zone *zone, 340 const ldns_rdf *dname, 341 ldns_rr_type type); 342 343 /** 344 * Prints the RRs in the dnssec name structure to the given 345 * file descriptor 346 * 347 * \param[in] out the file descriptor to print to 348 * \param[in] name the name structure to print the contents of 349 */ 350 void ldns_dnssec_name_print(FILE *out, const ldns_dnssec_name *name); 351 352 /** 353 * Prints the RRs in the dnssec name structure to the given 354 * file descriptor 355 * 356 * \param[in] out the file descriptor to print to 357 * \param[in] fmt the format of the textual representation 358 * \param[in] name the name structure to print the contents of 359 */ 360 void ldns_dnssec_name_print_fmt(FILE *out, 361 const ldns_output_format *fmt, const ldns_dnssec_name *name); 362 363 /** 364 * Creates a new dnssec_zone structure 365 * \return the allocated structure 366 */ 367 ldns_dnssec_zone *ldns_dnssec_zone_new(void); 368 369 /** 370 * Create a new dnssec zone from a file. 371 * \param[out] z the new zone 372 * \param[in] *fp the filepointer to use 373 * \param[in] *origin the zones' origin 374 * \param[in] c default class to use (IN) 375 * \param[in] ttl default ttl to use 376 * 377 * \return ldns_status mesg with an error or LDNS_STATUS_OK 378 */ 379 ldns_status ldns_dnssec_zone_new_frm_fp(ldns_dnssec_zone** z, FILE* fp, 380 const ldns_rdf* origin, uint32_t ttl, ldns_rr_class c); 381 382 /** 383 * Create a new dnssec zone from a file, keep track of the line numbering 384 * \param[out] z the new zone 385 * \param[in] *fp the filepointer to use 386 * \param[in] *origin the zones' origin 387 * \param[in] ttl default ttl to use 388 * \param[in] c default class to use (IN) 389 * \param[out] line_nr used for error msg, to get to the line number 390 * 391 * \return ldns_status mesg with an error or LDNS_STATUS_OK 392 */ 393 ldns_status ldns_dnssec_zone_new_frm_fp_l(ldns_dnssec_zone** z, FILE* fp, 394 const ldns_rdf* origin, uint32_t ttl, ldns_rr_class c, int* line_nr); 395 396 /** 397 * Frees the given zone structure, and its rbtree of dnssec_names 398 * Individual ldns_rr RRs within those names are *not* freed 399 * \param[in] *zone the zone to free 400 */ 401 void ldns_dnssec_zone_free(ldns_dnssec_zone *zone); 402 403 /** 404 * Frees the given zone structure, and its rbtree of dnssec_names 405 * Individual ldns_rr RRs within those names are also freed 406 * \param[in] *zone the zone to free 407 */ 408 void ldns_dnssec_zone_deep_free(ldns_dnssec_zone *zone); 409 410 /** 411 * Adds the given RR to the zone. 412 * It find whether there is a dnssec_name with that name present. 413 * If so, add it to that, if not create a new one. 414 * Special handling of NSEC and RRSIG provided 415 * 416 * \param[in] zone the zone to add the RR to 417 * \param[in] rr The RR to add 418 * \return LDNS_STATUS_OK on success, an error code otherwise 419 */ 420 ldns_status ldns_dnssec_zone_add_rr(ldns_dnssec_zone *zone, 421 ldns_rr *rr); 422 423 /** 424 * Prints the rbtree of ldns_dnssec_name structures to the file descriptor 425 * 426 * \param[in] out the file descriptor to print the names to 427 * \param[in] tree the tree of ldns_dnssec_name structures to print 428 * \param[in] print_soa if true, print SOA records, if false, skip them 429 */ 430 void ldns_dnssec_zone_names_print(FILE *out, const ldns_rbtree_t *tree, bool print_soa); 431 432 /** 433 * Prints the rbtree of ldns_dnssec_name structures to the file descriptor 434 * 435 * \param[in] out the file descriptor to print the names to 436 * \param[in] fmt the format of the textual representation 437 * \param[in] tree the tree of ldns_dnssec_name structures to print 438 * \param[in] print_soa if true, print SOA records, if false, skip them 439 */ 440 void ldns_dnssec_zone_names_print_fmt(FILE *out, const ldns_output_format *fmt, 441 const ldns_rbtree_t *tree, bool print_soa); 442 443 /** 444 * Prints the complete zone to the given file descriptor 445 * 446 * \param[in] out the file descriptor to print to 447 * \param[in] zone the dnssec_zone to print 448 */ 449 void ldns_dnssec_zone_print(FILE *out, const ldns_dnssec_zone *zone); 450 451 /** 452 * Prints the complete zone to the given file descriptor 453 * 454 * \param[in] out the file descriptor to print to 455 * \param[in] fmt the format of the textual representation 456 * \param[in] zone the dnssec_zone to print 457 */ 458 void ldns_dnssec_zone_print_fmt(FILE *out, 459 const ldns_output_format *fmt, const ldns_dnssec_zone *zone); 460 461 /** 462 * Adds explicit dnssec_name structures for the empty nonterminals 463 * in this zone. (this is needed for NSEC3 generation) 464 * 465 * \param[in] zone the zone to check for empty nonterminals 466 * return LDNS_STATUS_OK on success. 467 */ 468 ldns_status ldns_dnssec_zone_add_empty_nonterminals(ldns_dnssec_zone *zone); 469 470 /** 471 * If a NSEC3PARAM is available in the apex, walks the zone and returns true 472 * on the first optout nsec3. 473 * 474 * \param[in] zone the zone to check for nsec3 optout records 475 * return true when the zone has at least one nsec3 optout record. 476 */ 477 bool ldns_dnssec_zone_is_nsec3_optout(const ldns_dnssec_zone* zone); 478 479 ldns_status ldns_dnssec_zone_verify_zonemd(ldns_dnssec_zone *zone); 480 481 #ifdef __cplusplus 482 } 483 #endif 484 485 #endif 486