1 /* Copyright (C) 2021 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
2
3 This program is free software: you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation, either version 3 of the License, or
6 (at your option) any later version.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12
13 You should have received a copy of the GNU General Public License
14 along with this program. If not, see <https://www.gnu.org/licenses/>.
15 */
16
17 #pragma once
18
19 #include "contrib/macros.h"
20 #include "contrib/mempattern.h"
21 #include "libknot/descriptor.h"
22 #include "libknot/dname.h"
23 #include "libknot/rrset.h"
24 #include "libknot/rdataset.h"
25
26 struct rr_data;
27
28 /*!
29 * \brief Structure representing one node in a domain name tree, i.e. one domain
30 * name in a zone.
31 */
32 typedef struct zone_node {
33 knot_dname_t *owner; /*!< Domain name being the owner of this node. */
34 struct zone_node *parent; /*!< Parent node in the name hierarchy. */
35
36 /*! \brief Array with data of RRSets belonging to this node. */
37 struct rr_data *rrs;
38
39 /*!
40 * \brief Previous node in canonical order. Only authoritative
41 * nodes or delegation points are referenced by this.
42 */
43 struct zone_node *prev;
44 union {
45 knot_dname_t *nsec3_hash; /*! Name of the NSEC3 corresponding to this node. */
46 struct zone_node *nsec3_node; /*! NSEC3 node corresponding to this node.
47 \warning This always points to first part of that bi-node!
48 assert(!(node->nsec3_node & NODE_FLAGS_SECOND)); */
49 };
50 knot_dname_t *nsec3_wildcard_name; /*! Name of NSEC3 node proving wildcard nonexistence. */
51 uint32_t children; /*!< Count of children nodes in DNS hierarchy. */
52 uint16_t rrset_count; /*!< Number of RRSets stored in the node. */
53 uint16_t flags; /*!< \ref node_flags enum. */
54 } zone_node_t;
55
56 /*!< \brief Glue node context. */
57 typedef struct {
58 const zone_node_t *node; /*!< Glue node. */
59 uint16_t ns_pos; /*!< Corresponding NS record position (for compression). */
60 bool optional; /*!< Optional glue indicator. */
61 } glue_t;
62
63 /*!< \brief Additional data. */
64 typedef struct {
65 glue_t *glues; /*!< Glue data. */
66 uint16_t count; /*!< Number of glue nodes. */
67 } additional_t;
68
69 /*!< \brief Structure storing RR data. */
70 struct rr_data {
71 uint32_t ttl; /*!< RRSet TTL. */
72 uint16_t type; /*!< RR type of data. */
73 knot_rdataset_t rrs; /*!< Data of given type. */
74 additional_t *additional; /*!< Additional nodes with glues. */
75 };
76
77 /*! \brief Flags used to mark nodes with some property. */
78 enum node_flags {
79 /*! \brief Node is authoritative, default. */
80 NODE_FLAGS_AUTH = 0 << 0,
81 /*! \brief Node is a delegation point (i.e. marking a zone cut). */
82 NODE_FLAGS_DELEG = 1 << 0,
83 /*! \brief Node is not authoritative (i.e. below a zone cut). */
84 NODE_FLAGS_NONAUTH = 1 << 1,
85 /*! \brief RRSIGs in node have been cryptographically validated by Knot. */
86 NODE_FLAGS_RRSIGS_VALID = 1 << 2,
87 /*! \brief Node is empty and will be deleted after update. */
88 NODE_FLAGS_EMPTY = 1 << 3,
89 /*! \brief Node has a wildcard child. */
90 NODE_FLAGS_WILDCARD_CHILD = 1 << 4,
91 /*! \brief Is this NSEC3 node compatible with zone's NSEC3PARAMS ? */
92 NODE_FLAGS_IN_NSEC3_CHAIN = 1 << 5,
93 /*! \brief Node is the zone Apex. */
94 NODE_FLAGS_APEX = 1 << 6,
95 /*! \brief The nsec3_node pointer is valid and and nsec3_hash pointer invalid. */
96 NODE_FLAGS_NSEC3_NODE = 1 << 7,
97 /*! \brief Is this i bi-node? */
98 NODE_FLAGS_BINODE = 1 << 8, // this value shall be fixed
99 /*! \brief Is this the second half of bi-node? */
100 NODE_FLAGS_SECOND = 1 << 9, // this value shall be fixed
101 /*! \brief The node shall be deleted. It's just not because it's a bi-node and the counterpart still exists. */
102 NODE_FLAGS_DELETED = 1 << 10,
103 /*! \brief The node or some node in subtree has some authoritative data in it (possibly also DS at deleg). */
104 NODE_FLAGS_SUBTREE_AUTH = 1 << 11,
105 /*! \brief The node or some node in subtree has any data in it, possibly just insec deleg. */
106 NODE_FLAGS_SUBTREE_DATA = 1 << 12,
107 };
108
109 typedef void (*node_addrem_cb)(zone_node_t *, void *);
110 typedef zone_node_t *(*node_new_cb)(const knot_dname_t *, void *);
111
112 /*!
113 * \brief Clears additional structure.
114 *
115 * \param additional Additional to clear.
116 */
117 void additional_clear(additional_t *additional);
118
119 /*!
120 * \brief Compares additional structures on equivalency.
121 */
122 bool additional_equal(additional_t *a, additional_t *b);
123
124 /*!
125 * \brief Creates and initializes new node structure.
126 *
127 * \param owner Node's owner, will be duplicated.
128 * \param binode Create bi-node.
129 * \param second The second part of the bi-node shall be used now.
130 * \param mm Memory context to use.
131 *
132 * \return Newly created node or NULL if an error occurred.
133 */
134 zone_node_t *node_new(const knot_dname_t *owner, bool binode, bool second, knot_mm_t *mm);
135
136 /*!
137 * \brief Synchronize contents of both binode's nodes.
138 *
139 * \param node Pointer to either of nodes in a binode.
140 * \param free_deleted When the unified node has DELETED flag, free it afterwards.
141 * \param mm Memory context.
142 */
143 void binode_unify(zone_node_t *node, bool free_deleted, knot_mm_t *mm);
144
145 /*!
146 * \brief This must be called before any change to either of the bi-node's node's rdatasets.
147 */
148 int binode_prepare_change(zone_node_t *node, knot_mm_t *mm);
149
150 /*!
151 * \brief Get the correct node of a binode.
152 *
153 * \param node Pointer to either of nodes in a binode.
154 * \param second Get the second node (first otherwise).
155 *
156 * \return Pointer to correct node.
157 */
binode_node(zone_node_t * node,bool second)158 inline static zone_node_t *binode_node(zone_node_t *node, bool second)
159 {
160 if (unlikely(node == NULL || !(node->flags & NODE_FLAGS_BINODE))) {
161 assert(node == NULL || !(node->flags & NODE_FLAGS_SECOND));
162 return node;
163 }
164 return node + (second - (int)((node->flags & NODE_FLAGS_SECOND) >> 9));
165 }
166
binode_first(zone_node_t * node)167 inline static zone_node_t *binode_first(zone_node_t *node)
168 {
169 return binode_node(node, false);
170 }
171
binode_node_as(zone_node_t * node,const zone_node_t * as)172 inline static zone_node_t *binode_node_as(zone_node_t *node, const zone_node_t *as)
173 {
174 assert(node == NULL || (as->flags & NODE_FLAGS_BINODE) == (node->flags & NODE_FLAGS_BINODE));
175 return binode_node(node, (as->flags & NODE_FLAGS_SECOND));
176 }
177
178 /*!
179 * \brief Return the other node from a bi-node.
180 *
181 * \param node A node in a bi-node.
182 *
183 * \return The counterpart node in the same bi-node.
184 */
185 zone_node_t *binode_counterpart(zone_node_t *node);
186
187 /*!
188 * \brief Return true if the rdataset of specified type is shared (shallow-copied) among both parts of bi-node.
189 */
190 bool binode_rdata_shared(zone_node_t *node, uint16_t type);
191
192 /*!
193 * \brief Return true if the additionals to rdataset of specified type are shared among both parts of bi-node.
194 */
195 bool binode_additional_shared(zone_node_t *node, uint16_t type);
196
197 /*!
198 * \brief Return true if the additionals are unchanged between two nodes (usually a bi-node).
199 */
200 bool binode_additionals_unchanged(zone_node_t *node, zone_node_t *counterpart);
201
202 /*!
203 * \brief Destroys allocated data within the node
204 * structure, but not the node itself.
205 *
206 * \param node Node that contains data to be destroyed.
207 * \param mm Memory context to use.
208 */
209 void node_free_rrsets(zone_node_t *node, knot_mm_t *mm);
210
211 /*!
212 * \brief Destroys the node structure.
213 *
214 * Does not destroy the data within the node.
215 *
216 * \param node Node to be destroyed.
217 * \param mm Memory context to use.
218 */
219 void node_free(zone_node_t *node, knot_mm_t *mm);
220
221 /*!
222 * \brief Adds an RRSet to the node. All data are copied. Owner and class are
223 * not used at all.
224 *
225 * \param node Node to add the RRSet to.
226 * \param rrset RRSet to add.
227 * \param mm Memory context to use.
228 *
229 * \return KNOT_E*
230 * \retval KNOT_ETTL RRSet TTL was updated.
231 */
232 int node_add_rrset(zone_node_t *node, const knot_rrset_t *rrset, knot_mm_t *mm);
233
234 /*!
235 * \brief Removes data for given RR type from node.
236 *
237 * \param node Node we want to delete from.
238 * \param type RR type to delete.
239 */
240 void node_remove_rdataset(zone_node_t *node, uint16_t type);
241
242 /*!
243 * \brief Remove all RRs from RRSet from the node.
244 *
245 * \param node Node to remove from.
246 * \param rrset RRSet with RRs to be removed.
247 * \param mm Memory context.
248 *
249 * \return KNOT_E*
250 */
251 int node_remove_rrset(zone_node_t *node, const knot_rrset_t *rrset, knot_mm_t *mm);
252
253 /*!
254 * \brief Returns the RRSet of the given type from the node. RRSet is allocated.
255 *
256 * \param node Node to get the RRSet from.
257 * \param type RR type of the RRSet to retrieve.
258 *
259 * \return RRSet from node \a node having type \a type, or NULL if no such
260 * RRSet exists in this node.
261 */
262 knot_rrset_t *node_create_rrset(const zone_node_t *node, uint16_t type);
263
264 /*!
265 * \brief Gets rdata set structure of given type from node.
266 *
267 * \param node Node to get data from.
268 * \param type RR type of data to get.
269 *
270 * \return Pointer to data if found, NULL otherwise.
271 */
272 knot_rdataset_t *node_rdataset(const zone_node_t *node, uint16_t type);
273
274 /*!
275 * \brief Returns parent node (fixing bi-node issue) of given node.
276 */
node_parent(const zone_node_t * node)277 inline static zone_node_t *node_parent(const zone_node_t *node)
278 {
279 return binode_node_as(node->parent, node);
280 }
281
282 /*!
283 * \brief Returns previous (lexicographically in same zone tree) node (fixing bi-node issue) of given node.
284 */
node_prev(const zone_node_t * node)285 inline static zone_node_t *node_prev(const zone_node_t *node)
286 {
287 return binode_node_as(node->prev, node);
288 }
289
290 /*!
291 * \brief Return node referenced by a glue.
292 *
293 * \param glue Glue in question.
294 * \param another_zone_node Another node from the same zone.
295 *
296 * \return Glue node.
297 */
glue_node(const glue_t * glue,const zone_node_t * another_zone_node)298 inline static const zone_node_t *glue_node(const glue_t *glue, const zone_node_t *another_zone_node)
299 {
300 return binode_node_as((zone_node_t *)glue->node, another_zone_node);
301 }
302
303 /*!
304 * \brief Add a flag to this node and all (grand-)parents until the flag is present.
305 */
node_set_flag_hierarch(zone_node_t * node,uint16_t fl)306 inline static void node_set_flag_hierarch(zone_node_t *node, uint16_t fl)
307 {
308 for (zone_node_t *i = node; i != NULL && (i->flags & fl) != fl; i = node_parent(i)) {
309 i->flags |= fl;
310 }
311 }
312
313 /*!
314 * \brief Checks whether node contains any RRSIG for given type.
315 *
316 * \param node Node to check in.
317 * \param type Type to check for.
318 *
319 * \return True/False.
320 */
321 bool node_rrtype_is_signed(const zone_node_t *node, uint16_t type);
322
323 /*!
324 * \brief Checks whether node contains RRSet for given type.
325 *
326 * \param node Node to check in.
327 * \param type Type to check for.
328 *
329 * \return True/False.
330 */
node_rrtype_exists(const zone_node_t * node,uint16_t type)331 inline static bool node_rrtype_exists(const zone_node_t *node, uint16_t type)
332 {
333 return node_rdataset(node, type) != NULL;
334 }
335
336 /*!
337 * \brief Checks whether node is empty. Node is empty when NULL or when no
338 * RRSets are in it.
339 *
340 * \param node Node to check in.
341 *
342 * \return True/False.
343 */
node_empty(const zone_node_t * node)344 inline static bool node_empty(const zone_node_t *node)
345 {
346 return node == NULL || node->rrset_count == 0;
347 }
348
349 /*!
350 * \brief Check whether two nodes have equal set of rrtypes.
351 *
352 * \param a A node.
353 * \param b Another node.
354 *
355 * \return True/False.
356 */
357 bool node_bitmap_equal(const zone_node_t *a, const zone_node_t *b);
358
359 /*!
360 * \brief Returns RRSet structure initialized with data from node.
361 *
362 * \param node Node containing RRSet.
363 * \param type RRSet type we want to get.
364 *
365 * \return RRSet structure with wanted type, or empty RRSet.
366 */
node_rrset(const zone_node_t * node,uint16_t type)367 static inline knot_rrset_t node_rrset(const zone_node_t *node, uint16_t type)
368 {
369 knot_rrset_t rrset;
370 for (uint16_t i = 0; node && i < node->rrset_count; ++i) {
371 if (node->rrs[i].type == type) {
372 struct rr_data *rr_data = &node->rrs[i];
373 knot_rrset_init(&rrset, node->owner, type, KNOT_CLASS_IN,
374 rr_data->ttl);
375 rrset.rrs = rr_data->rrs;
376 rrset.additional = rr_data->additional;
377 return rrset;
378 }
379 }
380 knot_rrset_init_empty(&rrset);
381 return rrset;
382 }
383
384 /*!
385 * \brief Returns RRSet structure initialized with data from node at position
386 * equal to \a pos.
387 *
388 * \param node Node containing RRSet.
389 * \param pos RRSet position we want to get.
390 *
391 * \return RRSet structure with data from wanted position, or empty RRSet.
392 */
node_rrset_at(const zone_node_t * node,size_t pos)393 static inline knot_rrset_t node_rrset_at(const zone_node_t *node, size_t pos)
394 {
395 knot_rrset_t rrset;
396 if (node == NULL || pos >= node->rrset_count) {
397 knot_rrset_init_empty(&rrset);
398 return rrset;
399 }
400
401 struct rr_data *rr_data = &node->rrs[pos];
402 knot_rrset_init(&rrset, node->owner, rr_data->type, KNOT_CLASS_IN,
403 rr_data->ttl);
404 rrset.rrs = rr_data->rrs;
405 rrset.additional = rr_data->additional;
406 return rrset;
407 }
408
409 /*!
410 * \brief Return the relevant NSEC3 node (if specified by adjusting), or NULL.
411 */
node_nsec3_get(const zone_node_t * node)412 static inline zone_node_t *node_nsec3_get(const zone_node_t *node)
413 {
414 if (!(node->flags & NODE_FLAGS_NSEC3_NODE) || node->nsec3_node == NULL) {
415 return NULL;
416 } else {
417 return binode_node_as(node->nsec3_node, node);
418 }
419 }
420