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