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
15extern "C" {
16#endif
17
18/**
19 * Singly linked list of rrs
20 */
21typedef struct ldns_struct_dnssec_rrs ldns_dnssec_rrs;
22struct ldns_struct_dnssec_rrs
23{
24	ldns_rr *rr;
25	ldns_dnssec_rrs *next;
26};
27
28/**
29 * Singly linked list of RRsets
30 */
31typedef struct ldns_struct_dnssec_rrsets ldns_dnssec_rrsets;
32struct 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 */
44typedef struct ldns_struct_dnssec_name ldns_dnssec_name;
45struct 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 */
91struct 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 applicible) */
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};
104typedef 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 */
110ldns_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 */
118void 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 */
126void 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 */
136ldns_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 */
144void ldns_dnssec_rrs_print(FILE *out, 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 */
153void ldns_dnssec_rrs_print_fmt(FILE *out,
154		const ldns_output_format *fmt, ldns_dnssec_rrs *rrs);
155
156/**
157 * Creates a new list (entry) of RRsets
158 * \return the newly allocated structure
159 */
160ldns_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 */
168void 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 */
176void 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 */
184ldns_rr_type ldns_dnssec_rrsets_type(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 */
193ldns_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 */
204ldns_status ldns_dnssec_rrsets_add_rr(ldns_dnssec_rrsets *rrsets, ldns_rr *rr);
205
206/**
207 * Print the given list of rrsets to the fiven 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 */
213void ldns_dnssec_rrsets_print(FILE *out,
214		ldns_dnssec_rrsets *rrsets,
215		bool follow);
216
217/**
218 * Print the given list of rrsets to the fiven 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 */
225void ldns_dnssec_rrsets_print_fmt(FILE *out,
226		const ldns_output_format *fmt,
227		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 */
235ldns_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 */
242ldns_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 */
250void 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 */
258void 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 */
266ldns_rdf *ldns_dnssec_name_name(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 */
275void 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 */
288bool ldns_dnssec_name_is_glue(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 */
296void 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 ordening.
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 *            ordening, 1 if it is the other way around, and 0 if they are
306 *            equal
307 */
308int 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 */
318ldns_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 */
328ldns_dnssec_rrsets *ldns_dnssec_name_find_rrset(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 */
339ldns_dnssec_rrsets *ldns_dnssec_zone_find_rrset(ldns_dnssec_zone *zone,
340									   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 */
350void ldns_dnssec_name_print(FILE *out, 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 */
360void ldns_dnssec_name_print_fmt(FILE *out,
361		const ldns_output_format *fmt, ldns_dnssec_name *name);
362
363/**
364 * Creates a new dnssec_zone structure
365 * \return the allocated structure
366 */
367ldns_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 */
379ldns_status ldns_dnssec_zone_new_frm_fp(ldns_dnssec_zone** z, FILE* fp,
380		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 */
393ldns_status ldns_dnssec_zone_new_frm_fp_l(ldns_dnssec_zone** z, FILE* fp,
394		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 */
401void 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 */
408void 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 */
420ldns_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 */
430void ldns_dnssec_zone_names_print(FILE *out, 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 */
440void ldns_dnssec_zone_names_print_fmt(FILE *out, const ldns_output_format *fmt,
441		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 */
449void ldns_dnssec_zone_print(FILE *out, 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 */
458void ldns_dnssec_zone_print_fmt(FILE *out,
459		const ldns_output_format *fmt, 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 */
468ldns_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 */
477bool ldns_dnssec_zone_is_nsec3_optout(ldns_dnssec_zone* zone);
478
479#ifdef __cplusplus
480}
481#endif
482
483#endif
484