xref: /freebsd/contrib/ldns/ldns/dnssec_zone.h (revision 9ed998a81bab54203604d08293089db875758686)
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