1 /*  Copyright (C) 2020 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 <assert.h>
20 #include <stdbool.h>
21 #include <stdint.h>
22 
23 #include "knot/zone/contents.h"
24 #include "knot/updates/zone-update.h"
25 #include "libdnssec/nsec.h"
26 
27 /*!
28  * \brief Parameters to be used in connect_nsec_nodes callback.
29  */
30 typedef struct {
31 	uint32_t ttl;          // TTL for NSEC(3) records
32 	zone_update_t *update; // The zone update for NSECs
33 	uint16_t nsec_type;    // NSEC or NSEC3
34 	const dnssec_nsec3_params_t *nsec3_params;
35 } nsec_chain_iterate_data_t;
36 
37 /*!
38  * \brief Used to control changeset iteration functions.
39  */
40 enum {
41 	NSEC_NODE_SKIP = 1,
42 };
43 
44 /*!
45  * \brief Callback used when creating NSEC chains.
46  */
47 typedef int (*chain_iterate_create_cb)(zone_node_t *, zone_node_t *,
48                                        nsec_chain_iterate_data_t *);
49 
50 /*!
51  * \brief Add all RR types from a node into the bitmap.
52  */
53 void bitmap_add_node_rrsets(dnssec_nsec_bitmap_t *bitmap, const zone_node_t *node,
54                             bool exact);
55 
56 /*!
57  * \brief Check that the NSEC(3) record in node A points to B.
58  *
59  * \param a      Node A.
60  * \param b      Node B.
61  * \param data   Validation context.
62  *
63  * \retval NSEC_NODE_SKIP            Node B is not part of NSEC chain, call again with A and B->next.
64  * \retval KNOT_DNSSEC_ENSEC_CHAIN   The NSEC(3) chain is broken.
65  * \return KNOT_E*
66  */
67 int nsec_check_connect_nodes(zone_node_t *a, zone_node_t *b,
68                              nsec_chain_iterate_data_t *data);
69 
70 /*!
71  * \brief Check NSEC connections of updated nodes.
72  *
73  * \param tree   Trie with updated nodes.
74  * \param data   Validation context.
75  *
76  * \return KNOT_DNSSEC_ENSEC_CHAIN, KNOT_E*
77  */
78 int nsec_check_new_connects(zone_tree_t *tree, nsec_chain_iterate_data_t *data);
79 
80 /*!
81  * \brief Check NSEC(3) bitmaps for updated nodes.
82  *
83  * \param nsec_ptrs   Trie with nodes to be checked.
84  * \param data        Validation context.
85  *
86  * \return KNOT_DNSSEC_ENSEC_BITMAP, KNOT_E*
87  */
88 int nsec_check_bitmaps(zone_tree_t *nsec_ptrs, nsec_chain_iterate_data_t *data);
89 
90 /*!
91  * \brief Call a function for each piece of the chain formed by sorted nodes.
92  *
93  * \note If the callback function returns anything other than KNOT_EOK, the
94  *       iteration is terminated and the error code is propagated.
95  *
96  * \param nodes     Zone nodes.
97  * \param callback  Callback function.
98  * \param data      Custom data supplied to the callback function.
99  *
100  * \return Error code, KNOT_EOK if successful.
101  */
102 int knot_nsec_chain_iterate_create(zone_tree_t *nodes,
103                                    chain_iterate_create_cb callback,
104                                    nsec_chain_iterate_data_t *data);
105 
106 /*!
107  * \brief Call the chain-connecting function for modified records and their neighbours.
108  *
109  * \param node_ptrs  Tree of those nodes that have ben changed by the update.
110  * \param callback   Callback function.
111  * \param cb_reconn  Callback for re-connecting "next" link to another node.
112  * \param data       Custom data supplied, incl. changeset to be updated.
113  *
114  * \retval KNOT_ENORECORD if the chain must be recreated from scratch.
115  * \return KNOT_E*
116  */
117 int knot_nsec_chain_iterate_fix(zone_tree_t *node_ptrs,
118                                 chain_iterate_create_cb callback,
119                                 chain_iterate_create_cb cb_reconn,
120                                 nsec_chain_iterate_data_t *data);
121 
122 /*!
123  * \brief Add entry for removed NSEC(3) and its RRSIG to the changeset.
124  *
125  * \param n          Node to extract NSEC(3) from.
126  * \param update     Update to add the old RR removal into.
127  *
128  * \return Error code, KNOT_EOK if successful.
129  */
130 int knot_nsec_changeset_remove(const zone_node_t *n, zone_update_t *update);
131 
132 /*!
133  * \brief Checks whether the node is empty or eventually contains only NSEC and
134  *        RRSIGs.
135  *
136  * \param n Node to check.
137  *
138  * \retval true if the node is empty or contains only NSEC and RRSIGs.
139  * \retval false otherwise.
140  */
141 bool knot_nsec_empty_nsec_and_rrsigs_in_node(const zone_node_t *n);
142 
143 /*!
144  * \brief Create new NSEC chain.
145  *
146  * \param update     Zone update to create NSEC chain for.
147  * \param ttl        TTL for created NSEC records.
148  *
149  * \return Error code, KNOT_EOK if successful.
150  */
151 int knot_nsec_create_chain(zone_update_t *update, uint32_t ttl);
152 
153 /*!
154  * \brief Fix existing NSEC chain to cover the changes in zone contents.
155  *
156  * \param update     Zone update to update NSEC chain for.
157  * \param ttl        TTL for created NSEC records.
158  *
159  * \retval KNOT_ENORECORD if the chain must be recreated from scratch.
160  * \return KNOT_E*
161  */
162 int knot_nsec_fix_chain(zone_update_t *update, uint32_t ttl);
163 
164 /*!
165  * \brief Validate NSEC chain in new_cont as whole.
166  *
167  * \note new_cont must have been adjusted already!
168  */
169 int knot_nsec_check_chain(zone_update_t *update);
170 
171 /*!
172  * \brief Validate NSEC chain in new_cont incrementally.
173  */
174 int knot_nsec_check_chain_fix(zone_update_t *update);
175