1238104Sdes/*
2238104Sdes * special zone file structures and functions for better dnssec handling
3238104Sdes *
4238104Sdes * A zone contains a SOA dnssec_zone_rrset, and an AVL tree of 'normal'
5238104Sdes * dnssec_zone_rrsets, indexed by name and type
6238104Sdes */
7238104Sdes
8238104Sdes#ifndef LDNS_DNSSEC_ZONE_H
9238104Sdes#define LDNS_DNSSEC_ZONE_H
10238104Sdes
11238104Sdes#include <ldns/rbtree.h>
12238104Sdes#include <ldns/host2str.h>
13238104Sdes
14238104Sdes#ifdef __cplusplus
15238104Sdesextern "C" {
16238104Sdes#endif
17238104Sdes
18238104Sdes/**
19238104Sdes * Singly linked list of rrs
20238104Sdes */
21238104Sdestypedef struct ldns_struct_dnssec_rrs ldns_dnssec_rrs;
22238104Sdesstruct ldns_struct_dnssec_rrs
23238104Sdes{
24238104Sdes	ldns_rr *rr;
25238104Sdes	ldns_dnssec_rrs *next;
26238104Sdes};
27238104Sdes
28238104Sdes/**
29238104Sdes * Singly linked list of RRsets
30238104Sdes */
31238104Sdestypedef struct ldns_struct_dnssec_rrsets ldns_dnssec_rrsets;
32238104Sdesstruct ldns_struct_dnssec_rrsets
33238104Sdes{
34238104Sdes	ldns_dnssec_rrs *rrs;
35238104Sdes	ldns_rr_type type;
36238104Sdes	ldns_dnssec_rrs *signatures;
37238104Sdes	ldns_dnssec_rrsets *next;
38238104Sdes};
39238104Sdes
40238104Sdes/**
41238104Sdes * Structure containing all resource records for a domain name
42238104Sdes * Including the derived NSEC3, if present
43238104Sdes */
44238104Sdestypedef struct ldns_struct_dnssec_name ldns_dnssec_name;
45238104Sdesstruct ldns_struct_dnssec_name
46238104Sdes{
47238104Sdes	/**
48238104Sdes	 * pointer to a dname containing the name.
49238104Sdes	 * Usually points to the owner name of the first RR of the first RRset
50238104Sdes	 */
51238104Sdes	ldns_rdf *name;
52238104Sdes	/**
53238104Sdes	 * Usually, the name is a pointer to the owner name of the first rr for
54238104Sdes	 * this name, but sometimes there is no actual data to point to,
55238104Sdes	 * for instance in
56238104Sdes	 * names representing empty nonterminals. If so, set alloced to true to
57238104Sdes	 * indicate that this data must also be freed when the name is freed
58238104Sdes	 */
59238104Sdes	bool name_alloced;
60238104Sdes	/**
61238104Sdes	 * The rrsets for this name
62238104Sdes	 */
63238104Sdes	ldns_dnssec_rrsets *rrsets;
64238104Sdes	/**
65238104Sdes	 * NSEC pointing to the next name (or NSEC3 pointing to the next NSEC3)
66238104Sdes	 */
67238104Sdes	ldns_rr *nsec;
68238104Sdes	/**
69238104Sdes	 * signatures for the NSEC record
70238104Sdes	 */
71238104Sdes	ldns_dnssec_rrs *nsec_signatures;
72238104Sdes	/**
73238104Sdes	 * Unlike what the name is_glue suggests, this field is set to true by
74238104Sdes	 * ldns_dnssec_zone_mark_glue() or ldns_dnssec_zone_mark_and_get_glue()
75238104Sdes	 * when the name, this dnssec_name struct represents, is occluded.
76238104Sdes	 * Names that contain other occluded rrsets and records with glue on
77238104Sdes	 * the delegation point will NOT have this bool set to true.
78238104Sdes	 * This field should NOT be read directly, but only via the
79238104Sdes	 * ldns_dnssec_name_is_glue() function!
80238104Sdes	 */
81238104Sdes	bool is_glue;
82238104Sdes	/**
83238104Sdes	 * pointer to store the hashed name (only used when in an NSEC3 zone
84238104Sdes	 */
85238104Sdes	ldns_rdf *hashed_name;
86238104Sdes};
87238104Sdes
88238104Sdes/**
89238104Sdes * Structure containing a dnssec zone
90238104Sdes */
91238104Sdesstruct ldns_struct_dnssec_zone {
92238104Sdes	/** points to the name containing the SOA RR */
93238104Sdes	ldns_dnssec_name *soa;
94238104Sdes	/** tree of ldns_dnssec_names */
95238104Sdes	ldns_rbtree_t *names;
96238104Sdes};
97238104Sdestypedef struct ldns_struct_dnssec_zone ldns_dnssec_zone;
98238104Sdes
99238104Sdes/**
100238104Sdes * Creates a new entry for 1 pointer to an rr and 1 pointer to the next rrs
101238104Sdes * \return the allocated data
102238104Sdes */
103246827Sdesldns_dnssec_rrs *ldns_dnssec_rrs_new(void);
104238104Sdes
105238104Sdes/**
106238104Sdes * Frees the list of rrs, but *not* the individual ldns_rr records
107238104Sdes * contained in the list
108238104Sdes *
109238104Sdes * \param[in] rrs the data structure to free
110238104Sdes */
111238104Sdesvoid ldns_dnssec_rrs_free(ldns_dnssec_rrs *rrs);
112238104Sdes
113238104Sdes/**
114238104Sdes * Frees the list of rrs, and the individual ldns_rr records
115238104Sdes * contained in the list
116238104Sdes *
117238104Sdes * \param[in] rrs the data structure to free
118238104Sdes */
119238104Sdesvoid ldns_dnssec_rrs_deep_free(ldns_dnssec_rrs *rrs);
120238104Sdes
121238104Sdes/**
122238104Sdes * Adds an RR to the list of RRs. The list will remain ordered
123238104Sdes *
124238104Sdes * \param[in] rrs the list to add to
125238104Sdes * \param[in] rr the RR to add
126238104Sdes * \return LDNS_STATUS_OK on success
127238104Sdes */
128238104Sdesldns_status ldns_dnssec_rrs_add_rr(ldns_dnssec_rrs *rrs, ldns_rr *rr);
129238104Sdes
130238104Sdes/**
131238104Sdes * Prints the given rrs to the file descriptor
132238104Sdes *
133238104Sdes * \param[in] out the file descriptor to print to
134238104Sdes * \param[in] rrs the list of RRs to print
135238104Sdes */
136238104Sdesvoid ldns_dnssec_rrs_print(FILE *out, ldns_dnssec_rrs *rrs);
137238104Sdes
138238104Sdes/**
139238104Sdes * Prints the given rrs to the file descriptor
140238104Sdes *
141238104Sdes * \param[in] out the file descriptor to print to
142238104Sdes * \param[in] fmt the format of the textual representation
143238104Sdes * \param[in] rrs the list of RRs to print
144238104Sdes */
145238104Sdesvoid ldns_dnssec_rrs_print_fmt(FILE *out,
146238104Sdes		const ldns_output_format *fmt, ldns_dnssec_rrs *rrs);
147238104Sdes
148238104Sdes/**
149238104Sdes * Creates a new list (entry) of RRsets
150238104Sdes * \return the newly allocated structure
151238104Sdes */
152246827Sdesldns_dnssec_rrsets *ldns_dnssec_rrsets_new(void);
153238104Sdes
154238104Sdes/**
155238104Sdes * Frees the list of rrsets and their rrs, but *not* the ldns_rr
156238104Sdes * records in the sets
157238104Sdes *
158238104Sdes * \param[in] rrsets the data structure to free
159238104Sdes */
160238104Sdesvoid ldns_dnssec_rrsets_free(ldns_dnssec_rrsets *rrsets);
161238104Sdes
162238104Sdes/**
163238104Sdes * Frees the list of rrsets and their rrs, and the ldns_rr
164238104Sdes * records in the sets
165238104Sdes *
166238104Sdes * \param[in] rrsets the data structure to free
167238104Sdes */
168238104Sdesvoid ldns_dnssec_rrsets_deep_free(ldns_dnssec_rrsets *rrsets);
169238104Sdes
170238104Sdes/**
171238104Sdes * Returns the rr type of the rrset (that is head of the given list)
172238104Sdes *
173238104Sdes * \param[in] rrsets the rrset to get the type of
174238104Sdes * \return the rr type
175238104Sdes */
176238104Sdesldns_rr_type ldns_dnssec_rrsets_type(ldns_dnssec_rrsets *rrsets);
177238104Sdes
178238104Sdes/**
179238104Sdes * Sets the RR type of the rrset (that is head of the given list)
180238104Sdes *
181238104Sdes * \param[in] rrsets the rrset to set the type of
182238104Sdes * \param[in] type the type to set
183238104Sdes * \return LDNS_STATUS_OK on success
184238104Sdes */
185238104Sdesldns_status ldns_dnssec_rrsets_set_type(ldns_dnssec_rrsets *rrsets,
186238104Sdes					   ldns_rr_type type);
187238104Sdes
188238104Sdes/**
189238104Sdes * Add an ldns_rr to the corresponding RRset in the given list of RRsets.
190238104Sdes * If it is not present, add it as a new RRset with 1 record.
191238104Sdes *
192238104Sdes * \param[in] rrsets the list of rrsets to add the RR to
193238104Sdes * \param[in] rr the rr to add to the list of rrsets
194238104Sdes * \return LDNS_STATUS_OK on success
195238104Sdes */
196238104Sdesldns_status ldns_dnssec_rrsets_add_rr(ldns_dnssec_rrsets *rrsets, ldns_rr *rr);
197238104Sdes
198238104Sdes/**
199238104Sdes * Print the given list of rrsets to the fiven file descriptor
200238104Sdes *
201238104Sdes * \param[in] out the file descriptor to print to
202238104Sdes * \param[in] rrsets the list of RRsets to print
203238104Sdes * \param[in] follow if set to false, only print the first RRset
204238104Sdes */
205238104Sdesvoid ldns_dnssec_rrsets_print(FILE *out,
206238104Sdes		ldns_dnssec_rrsets *rrsets,
207238104Sdes		bool follow);
208238104Sdes
209238104Sdes/**
210238104Sdes * Print the given list of rrsets to the fiven file descriptor
211238104Sdes *
212238104Sdes * \param[in] out the file descriptor to print to
213238104Sdes * \param[in] fmt the format of the textual representation
214238104Sdes * \param[in] rrsets the list of RRsets to print
215238104Sdes * \param[in] follow if set to false, only print the first RRset
216238104Sdes */
217238104Sdesvoid ldns_dnssec_rrsets_print_fmt(FILE *out,
218238104Sdes		const ldns_output_format *fmt,
219238104Sdes		ldns_dnssec_rrsets *rrsets,
220238104Sdes		bool follow);
221238104Sdes
222238104Sdes
223238104Sdes/**
224238104Sdes * Create a new data structure for a dnssec name
225238104Sdes * \return the allocated structure
226238104Sdes */
227246827Sdesldns_dnssec_name *ldns_dnssec_name_new(void);
228238104Sdes
229238104Sdes/**
230238104Sdes * Create a new data structure for a dnssec name for the given RR
231238104Sdes *
232238104Sdes * \param[in] rr the RR to derive properties from, and to add to the name
233238104Sdes */
234238104Sdesldns_dnssec_name *ldns_dnssec_name_new_frm_rr(ldns_rr *rr);
235238104Sdes
236238104Sdes/**
237238104Sdes * Frees the name structure and its rrs and rrsets.
238238104Sdes * Individual ldns_rr records therein are not freed
239238104Sdes *
240238104Sdes * \param[in] name the structure to free
241238104Sdes */
242238104Sdesvoid ldns_dnssec_name_free(ldns_dnssec_name *name);
243238104Sdes
244238104Sdes/**
245238104Sdes * Frees the name structure and its rrs and rrsets.
246238104Sdes * Individual ldns_rr records contained in the name are also freed
247238104Sdes *
248238104Sdes * \param[in] name the structure to free
249238104Sdes */
250238104Sdesvoid ldns_dnssec_name_deep_free(ldns_dnssec_name *name);
251238104Sdes
252238104Sdes/**
253238104Sdes * Returns the domain name of the given dnssec_name structure
254238104Sdes *
255238104Sdes * \param[in] name the dnssec name to get the domain name from
256238104Sdes * \return the domain name
257238104Sdes */
258238104Sdesldns_rdf *ldns_dnssec_name_name(ldns_dnssec_name *name);
259238104Sdes
260238104Sdes
261238104Sdes/**
262238104Sdes * Sets the domain name of the given dnssec_name structure
263238104Sdes *
264238104Sdes * \param[in] name the dnssec name to set the domain name of
265238104Sdes * \param[in] dname the domain name to set it to. This data is *not* copied.
266238104Sdes */
267238104Sdesvoid ldns_dnssec_name_set_name(ldns_dnssec_name *name,
268238104Sdes						 ldns_rdf *dname);
269238104Sdes/**
270238104Sdes * Returns if dnssec_name structure is marked as glue.
271238104Sdes * The ldns_dnssec_zone_mark_glue() function has to be called on a zone before
272238104Sdes * using this function.
273238104Sdes * Only names that have only glue rrsets will be marked.
274238104Sdes * Names that have other occluded rrsets and names containing glue on the
275238104Sdes * delegation point will NOT be marked!
276238104Sdes *
277238104Sdes * \param[in] name the dnssec name to get the domain name from
278238104Sdes * \return true if the structure is marked as glue, false otherwise.
279238104Sdes */
280238104Sdesbool ldns_dnssec_name_is_glue(ldns_dnssec_name *name);
281238104Sdes
282238104Sdes/**
283238104Sdes * Sets the NSEC(3) RR of the given dnssec_name structure
284238104Sdes *
285238104Sdes * \param[in] name the dnssec name to set the domain name of
286238104Sdes * \param[in] nsec the nsec rr to set it to. This data is *not* copied.
287238104Sdes */
288238104Sdesvoid ldns_dnssec_name_set_nsec(ldns_dnssec_name *name, ldns_rr *nsec);
289238104Sdes
290238104Sdes/**
291238104Sdes * Compares the domain names of the two arguments in their
292238104Sdes * canonical ordening.
293238104Sdes *
294238104Sdes * \param[in] a The first dnssec_name to compare
295238104Sdes * \param[in] b The second dnssec_name to compare
296238104Sdes * \return -1 if the domain name of a comes before that of b in canonical
297238104Sdes *            ordening, 1 if it is the other way around, and 0 if they are
298238104Sdes *            equal
299238104Sdes */
300238104Sdesint ldns_dnssec_name_cmp(const void *a, const void *b);
301238104Sdes
302238104Sdes/**
303238104Sdes * Inserts the given rr at the right place in the current dnssec_name
304238104Sdes * No checking is done whether the name matches
305238104Sdes *
306238104Sdes * \param[in] name The ldns_dnssec_name to add the RR to
307238104Sdes * \param[in] rr The RR to add
308238104Sdes * \return LDNS_STATUS_OK on success, error code otherwise
309238104Sdes */
310238104Sdesldns_status ldns_dnssec_name_add_rr(ldns_dnssec_name *name,
311238104Sdes							 ldns_rr *rr);
312238104Sdes
313238104Sdes/**
314238104Sdes * Find the RRset with the given type in within this name structure
315238104Sdes *
316238104Sdes * \param[in] name the name to find the RRset in
317238104Sdes * \param[in] type the type of the RRset to find
318238104Sdes * \return the RRset, or NULL if not present
319238104Sdes */
320238104Sdesldns_dnssec_rrsets *ldns_dnssec_name_find_rrset(ldns_dnssec_name *name,
321238104Sdes									   ldns_rr_type type);
322238104Sdes
323238104Sdes/**
324238104Sdes * Find the RRset with the given name and type in the zone
325238104Sdes *
326238104Sdes * \param[in] zone the zone structure to find the RRset in
327238104Sdes * \param[in] dname the domain name of the RRset to find
328238104Sdes * \param[in] type the type of the RRset to find
329238104Sdes * \return the RRset, or NULL if not present
330238104Sdes */
331238104Sdesldns_dnssec_rrsets *ldns_dnssec_zone_find_rrset(ldns_dnssec_zone *zone,
332238104Sdes									   ldns_rdf *dname,
333238104Sdes									   ldns_rr_type type);
334238104Sdes
335238104Sdes/**
336238104Sdes * Prints the RRs in the  dnssec name structure to the given
337238104Sdes * file descriptor
338238104Sdes *
339238104Sdes * \param[in] out the file descriptor to print to
340238104Sdes * \param[in] name the name structure to print the contents of
341238104Sdes */
342238104Sdesvoid ldns_dnssec_name_print(FILE *out, ldns_dnssec_name *name);
343238104Sdes
344238104Sdes/**
345238104Sdes * Prints the RRs in the  dnssec name structure to the given
346238104Sdes * file descriptor
347238104Sdes *
348238104Sdes * \param[in] out the file descriptor to print to
349238104Sdes * \param[in] fmt the format of the textual representation
350238104Sdes * \param[in] name the name structure to print the contents of
351238104Sdes */
352238104Sdesvoid ldns_dnssec_name_print_fmt(FILE *out,
353238104Sdes		const ldns_output_format *fmt, ldns_dnssec_name *name);
354238104Sdes
355238104Sdes/**
356238104Sdes * Creates a new dnssec_zone structure
357238104Sdes * \return the allocated structure
358238104Sdes */
359246827Sdesldns_dnssec_zone *ldns_dnssec_zone_new(void);
360238104Sdes
361238104Sdes/**
362238104Sdes * Create a new dnssec zone from a file.
363238104Sdes * \param[out] z the new zone
364238104Sdes * \param[in] *fp the filepointer to use
365238104Sdes * \param[in] *origin the zones' origin
366238104Sdes * \param[in] c default class to use (IN)
367238104Sdes * \param[in] ttl default ttl to use
368238104Sdes *
369238104Sdes * \return ldns_status mesg with an error or LDNS_STATUS_OK
370238104Sdes */
371238104Sdesldns_status ldns_dnssec_zone_new_frm_fp(ldns_dnssec_zone** z, FILE* fp,
372238104Sdes		ldns_rdf* origin, uint32_t ttl, ldns_rr_class c);
373238104Sdes
374238104Sdes/**
375238104Sdes * Create a new dnssec zone from a file, keep track of the line numbering
376238104Sdes * \param[out] z the new zone
377238104Sdes * \param[in] *fp the filepointer to use
378238104Sdes * \param[in] *origin the zones' origin
379238104Sdes * \param[in] ttl default ttl to use
380238104Sdes * \param[in] c default class to use (IN)
381238104Sdes * \param[out] line_nr used for error msg, to get to the line number
382238104Sdes *
383238104Sdes * \return ldns_status mesg with an error or LDNS_STATUS_OK
384238104Sdes */
385238104Sdesldns_status ldns_dnssec_zone_new_frm_fp_l(ldns_dnssec_zone** z, FILE* fp,
386238104Sdes		ldns_rdf* origin, uint32_t ttl, ldns_rr_class c, int* line_nr);
387238104Sdes
388238104Sdes/**
389238104Sdes * Frees the given zone structure, and its rbtree of dnssec_names
390238104Sdes * Individual ldns_rr RRs within those names are *not* freed
391238104Sdes * \param[in] *zone the zone to free
392238104Sdes */
393238104Sdesvoid ldns_dnssec_zone_free(ldns_dnssec_zone *zone);
394238104Sdes
395238104Sdes/**
396238104Sdes * Frees the given zone structure, and its rbtree of dnssec_names
397238104Sdes * Individual ldns_rr RRs within those names are also freed
398238104Sdes * \param[in] *zone the zone to free
399238104Sdes */
400238104Sdesvoid ldns_dnssec_zone_deep_free(ldns_dnssec_zone *zone);
401238104Sdes
402238104Sdes/**
403238104Sdes * Adds the given RR to the zone.
404238104Sdes * It find whether there is a dnssec_name with that name present.
405238104Sdes * If so, add it to that, if not create a new one.
406238104Sdes * Special handling of NSEC and RRSIG provided
407238104Sdes *
408238104Sdes * \param[in] zone the zone to add the RR to
409238104Sdes * \param[in] rr The RR to add
410238104Sdes * \return LDNS_STATUS_OK on success, an error code otherwise
411238104Sdes */
412238104Sdesldns_status ldns_dnssec_zone_add_rr(ldns_dnssec_zone *zone,
413238104Sdes							 ldns_rr *rr);
414238104Sdes
415238104Sdes/**
416238104Sdes * Prints the rbtree of ldns_dnssec_name structures to the file descriptor
417238104Sdes *
418238104Sdes * \param[in] out the file descriptor to print the names to
419238104Sdes * \param[in] tree the tree of ldns_dnssec_name structures to print
420238104Sdes * \param[in] print_soa if true, print SOA records, if false, skip them
421238104Sdes */
422238104Sdesvoid ldns_dnssec_zone_names_print(FILE *out, ldns_rbtree_t *tree, bool print_soa);
423238104Sdes
424238104Sdes/**
425238104Sdes * Prints the rbtree of ldns_dnssec_name structures to the file descriptor
426238104Sdes *
427238104Sdes * \param[in] out the file descriptor to print the names to
428238104Sdes * \param[in] fmt the format of the textual representation
429238104Sdes * \param[in] tree the tree of ldns_dnssec_name structures to print
430238104Sdes * \param[in] print_soa if true, print SOA records, if false, skip them
431238104Sdes */
432238104Sdesvoid ldns_dnssec_zone_names_print_fmt(FILE *out, const ldns_output_format *fmt,
433238104Sdes		ldns_rbtree_t *tree, bool print_soa);
434238104Sdes
435238104Sdes/**
436238104Sdes * Prints the complete zone to the given file descriptor
437238104Sdes *
438238104Sdes * \param[in] out the file descriptor to print to
439238104Sdes * \param[in] zone the dnssec_zone to print
440238104Sdes */
441238104Sdesvoid ldns_dnssec_zone_print(FILE *out, ldns_dnssec_zone *zone);
442238104Sdes
443238104Sdes/**
444238104Sdes * Prints the complete zone to the given file descriptor
445238104Sdes *
446238104Sdes * \param[in] out the file descriptor to print to
447238104Sdes * \param[in] fmt the format of the textual representation
448238104Sdes * \param[in] zone the dnssec_zone to print
449238104Sdes */
450238104Sdesvoid ldns_dnssec_zone_print_fmt(FILE *out,
451238104Sdes		const ldns_output_format *fmt, ldns_dnssec_zone *zone);
452238104Sdes
453238104Sdes/**
454238104Sdes * Adds explicit dnssec_name structures for the empty nonterminals
455238104Sdes * in this zone. (this is needed for NSEC3 generation)
456238104Sdes *
457238104Sdes * \param[in] zone the zone to check for empty nonterminals
458238104Sdes * return LDNS_STATUS_OK on success.
459238104Sdes */
460238104Sdesldns_status ldns_dnssec_zone_add_empty_nonterminals(ldns_dnssec_zone *zone);
461238104Sdes
462238104Sdes/**
463238104Sdes * If a NSEC3PARAM is available in the apex, walks the zone and returns true
464238104Sdes * on the first optout nsec3.
465238104Sdes *
466238104Sdes * \param[in] zone the zone to check for nsec3 optout records
467238104Sdes * return true when the zone has at least one nsec3 optout record.
468238104Sdes */
469238104Sdesbool ldns_dnssec_zone_is_nsec3_optout(ldns_dnssec_zone* zone);
470238104Sdes
471238104Sdes#ifdef __cplusplus
472238104Sdes}
473238104Sdes#endif
474238104Sdes
475238104Sdes#endif
476