contents.h 10.4 KB
Newer Older
1
/*  Copyright (C) 2019 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
Lubos Slovak's avatar
Lubos Slovak committed
2 3 4 5 6 7 8 9 10 11 12 13

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    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/>.
Lubos Slovak's avatar
Lubos Slovak committed
15
 */
16

17
#pragma once
18

19
#include "libdnssec/nsec.h"
20
#include "libknot/rrtype/nsec3param.h"
21 22
#include "knot/zone/node.h"
#include "knot/zone/zone-tree.h"
23

24
enum zone_contents_find_dname_result {
25 26
	ZONE_NAME_NOT_FOUND = 0,
	ZONE_NAME_FOUND     = 1
27
};
28

29
typedef struct zone_contents {
30
	zone_node_t *apex;       /*!< Apex node of the zone (holding SOA) */
31

32 33
	zone_tree_t *nodes;
	zone_tree_t *nsec3_nodes;
34

35
	dnssec_nsec3_params_t nsec3_params;
36
	size_t size;
37
	uint32_t max_ttl;
38
	bool dnssec;
39
} zone_contents_t;
40

41 42 43
/*!
 * \brief Signature of callback for zone contents apply functions.
 */
44
typedef int (*zone_contents_apply_cb_t)(zone_node_t *node, void *data);
45

46 47 48 49 50 51 52
/*!
 * \brief Allocate and create new zone contents.
 *
 * \param apex_name  Name of the root node.
 *
 * \return New contents or NULL on error.
 */
53
zone_contents_t *zone_contents_new(const knot_dname_t *apex_name);
54

55 56 57 58 59 60 61 62 63 64
/*!
 * \brief Add an RR to contents.
 *
 * \param z   Contents to add to.
 * \param rr  The RR to add.
 * \param n   Node to which the RR has been added to on success, unchanged otherwise.
 *
 * \return KNOT_E*
 */
int zone_contents_add_rr(zone_contents_t *z, const knot_rrset_t *rr, zone_node_t **n);
65

66 67 68 69 70 71 72 73 74 75 76
/*!
 * \brief Remove an RR from contents.
 *
 * \param z   Contents to remove from.
 * \param rr  The RR to remove.
 * \param n   Node from which the RR to be removed from on success, unchanged otherwise.
 *
 * \return KNOT_E*
 */
int zone_contents_remove_rr(zone_contents_t *z, const knot_rrset_t *rr, zone_node_t **n);

77 78 79 80 81 82 83 84 85
/*!
 * \brief Get the node with this RR (the RR's owner).
 *
 * \param zone   Contents to add to.
 * \param rrset  The RR to add.
 *
 * \return The searched node if it exists, a new added empty node or NULL on error.
 */
zone_node_t *zone_contents_get_node_for_rr(zone_contents_t *zone, const knot_rrset_t *rrset);
86

87 88 89
/*!
 * \brief Tries to find a node with the specified name in the zone.
 *
90
 * \param contents Zone where the name should be searched for.
91 92 93 94
 * \param name Name to find.
 *
 * \return Corresponding node if found, NULL otherwise.
 */
95 96
const zone_node_t *zone_contents_find_node(const zone_contents_t *contents, const knot_dname_t *name);

97 98 99 100 101 102 103 104
/*!
 * \brief Find a node in which the given rrset may be inserted,
 *
 * \param contents   Zone contents.
 * \param rrset      RRSet to be inserted later.
 *
 * \return Existing node in zone which the RRSet may be inserted in; or NULL if none present.
 */
105
zone_node_t *zone_contents_find_node_for_rr(zone_contents_t *contents, const knot_rrset_t *rrset);
106 107

/*!
108
 * \brief Tries to find a node by owner in the zone contents.
109
 *
110 111 112 113 114 115 116 117 118 119
 * \param[in]  contents  Zone to search for the name.
 * \param[in]  name      Domain name to search for.
 * \param[out] match     Matching node or NULL.
 * \param[out] closest   Closest matching name in the zone.
 *                       May match \a match if found exactly.
 * \param[out] previous  Previous domain name in canonical order.
 *                       Always previous, won't match \a match.
 *
 * \note The encloser and previous mustn't be used directly for DNSSEC proofs.
 *       These nodes may be empty non-terminals or not authoritative.
120
 *
121 122
 * \retval ZONE_NAME_FOUND if node with owner \a name was found.
 * \retval ZONE_NAME_NOT_FOUND if it was not found.
Marek Vavrusa's avatar
Marek Vavrusa committed
123
 * \retval KNOT_EINVAL
124
 * \retval KNOT_EOUTOFZONE
125
 */
126
int zone_contents_find_dname(const zone_contents_t *contents,
127
                             const knot_dname_t *name,
128 129
                             const zone_node_t **match,
                             const zone_node_t **closest,
130
                             const zone_node_t **previous);
131 132 133 134 135

/*!
 * \brief Tries to find a node with the specified name among the NSEC3 nodes
 *        of the zone.
 *
136
 * \note This function is identical to zone_contents_get_nsec3_node(), only it
137 138
 *       returns constant reference.
 *
139
 * \param contents Zone where the name should be searched for.
140 141 142 143
 * \param name Name to find.
 *
 * \return Corresponding node if found, NULL otherwise.
 */
144 145
const zone_node_t *zone_contents_find_nsec3_node(const zone_contents_t *contents,
                                                 const knot_dname_t *name);
146 147 148 149 150 151 152 153

/*!
 * \brief Finds NSEC3 node and previous NSEC3 node in canonical order,
 *        corresponding to the given domain name.
 *
 * This functions creates a NSEC3 hash of \a name and tries to find NSEC3 node
 * with the hashed domain name as owner.
 *
154
 * \param[in] contents Zone to search in.
155 156 157 158 159 160
 * \param[in] name Domain name to get the corresponding NSEC3 nodes for.
 * \param[out] nsec3_node NSEC3 node corresponding to \a name (if found,
 *                        otherwise this may be an arbitrary NSEC3 node).
 * \param[out] nsec3_previous The NSEC3 node immediately preceding hashed domain
 *                            name corresponding to \a name in canonical order.
 *
161 162
 * \retval ZONE_NAME_FOUND if the corresponding NSEC3 node was found.
 * \retval ZONE_NAME_NOT_FOUND if it was not found.
Marek Vavrusa's avatar
Marek Vavrusa committed
163
 * \retval KNOT_EINVAL
Lubos Slovak's avatar
Lubos Slovak committed
164 165 166
 * \retval KNOT_ENSEC3PAR
 * \retval KNOT_ECRYPTO
 * \retval KNOT_ERROR
167
 */
168 169 170 171
int zone_contents_find_nsec3_for_name(const zone_contents_t *contents,
                                      const knot_dname_t *name,
                                      const zone_node_t **nsec3_node,
                                      const zone_node_t **nsec3_previous);
172

173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197
/*!
 * \brief Finds NSEC3 node and previous NSEC3 node to specified NSEC3 name.
 *
 * Like previous function, but the NSEC3 hashed-name is already known.
 *
 * \param zone             Zone contents to search in,
 * \param nsec3_name       NSEC3 name to be searched for.
 * \param nsec3_node       Out: NSEC3 node found.
 * \param nsec3_previous   Out: previous NSEC3 node.
 *
 * \return ZONE_NAME_FOUND, ZONE_NAME_NOT_FOUND, KNOT_E*
 */
int zone_contents_find_nsec3(const zone_contents_t *zone,
                             const knot_dname_t *nsec3_name,
                             const zone_node_t **nsec3_node,
                             const zone_node_t **nsec3_previous);

/*!
 * \brief For specified node, give a wildcard child if exists in zone.
 *
 * \param contents   Zone contents.
 * \param parent     Given parent node.
 *
 * \return Node being a wildcard child; or NULL.
 */
198 199
const zone_node_t *zone_contents_find_wildcard_child(const zone_contents_t *contents,
                                                     const zone_node_t *parent);
200

201 202 203 204 205 206 207 208 209 210 211 212 213
/*!
 * \brief For given name, find either exactly matching node in zone, or a matching wildcard node.
 *
 * \param contents   Zone contents to be searched in.
 * \param find       Name to be searched for.
 * \param found      Out: a node that either has owner "find" or is matching wildcard node.
 *
 * \return true iff found something
 */
bool zone_contents_find_node_or_wildcard(const zone_contents_t *contents,
                                         const knot_dname_t *find,
                                         const zone_node_t **found);

214 215 216
/*!
 * \brief Applies the given function to each regular node in the zone.
 *
217
 * \param contents Nodes of this zone will be used as parameters for the function.
218 219 220
 * \param function Function to be applied to each node of the zone.
 * \param data Arbitrary data to be passed to the function.
 */
221 222
int zone_contents_apply(zone_contents_t *contents,
                        zone_contents_apply_cb_t function, void *data);
223 224 225 226

/*!
 * \brief Applies the given function to each NSEC3 node in the zone.
 *
227 228
 * \param contents NSEC3 nodes of this zone will be used as parameters for the
 *                 function.
229 230 231
 * \param function Function to be applied to each node of the zone.
 * \param data Arbitrary data to be passed to the function.
 */
232 233
int zone_contents_nsec3_apply(zone_contents_t *contents,
                              zone_contents_apply_cb_t function, void *data);
234 235 236 237 238 239 240 241 242 243 244 245 246

/*!
 * \brief Creates a shallow copy of the zone (no stored data are copied).
 *
 * This function creates a new zone structure in \a to, creates new trees for
 * regular nodes and for NSEC3 nodes, creates new hash table and a new domain
 * table. It also fills these structures with the exact same data as the
 * original zone is - no copying of stored data is done, just pointers are
 * copied.
 *
 * \param from Original zone.
 * \param to Copy of the zone.
 *
Lubos Slovak's avatar
Lubos Slovak committed
247
 * \retval KNOT_EOK
Marek Vavrusa's avatar
Marek Vavrusa committed
248
 * \retval KNOT_EINVAL
Lubos Slovak's avatar
Lubos Slovak committed
249
 * \retval KNOT_ENOMEM
250
 */
251
int zone_contents_shallow_copy(const zone_contents_t *from, zone_contents_t **to);
252

253 254 255 256 257
/*!
 * \brief Deallocate directly owned data of zone contents.
 *
 * \param contents  Zone contents to free.
 */
258
void zone_contents_free(zone_contents_t *contents);
259

260 261 262 263 264
/*!
 * \brief Deallocate node RRSets inside the trees, then call zone_contents_free.
 *
 * \param contents  Zone contents to free.
 */
265
void zone_contents_deep_free(zone_contents_t *contents);
266

267 268
/*!
 * \brief Fetch zone serial.
Jan Včelák's avatar
Jan Včelák committed
269
 *
270
 * \param zone Zone.
Jan Včelák's avatar
Jan Včelák committed
271
 *
272 273
 * \return serial or 0
 */
274
uint32_t zone_contents_serial(const zone_contents_t *zone);
275

276 277 278 279 280 281 282 283 284 285
/*!
 * \brief Adjust zone serial.
 *
 * Works only if there is a SOA in given contents.
 *
 * \param zone        Zone.
 * \param new_serial  New serial to be set.
 */
void zone_contents_set_soa_serial(zone_contents_t *zone, uint32_t new_serial);

286 287 288 289 290
/*!
 * \brief Load parameters from NSEC3PARAM record into contents->nsec3param structure.
 */
int zone_contents_load_nsec3param(zone_contents_t *contents);

291 292 293
/*!
 * \brief Return true if zone is empty.
 */
294 295
bool zone_contents_is_empty(const zone_contents_t *zone);

296 297 298 299 300 301 302
/*!
 * \brief Measure zone contents size.
 *
 * Size is measured in uncompressed wire format. Measured size is saved into
 * zone contents structure.
 * \return Measured size
 */
303 304
size_t zone_contents_measure_size(zone_contents_t *zone);

305 306 307 308 309 310 311 312 313
/*!
 * \brief Obtain maximal TTL above all the records in zone.
 *
 * The value is also stored in zone_contents structure.
 *
 * \param zone   Zone in question.
 * \return Maximal TTL.
 */
uint32_t zone_contents_max_ttl(zone_contents_t *zone);