summaryrefslogtreecommitdiffstats
path: root/src/knot/zone/zone.h
blob: ae8991e5cdf0c5bc08fc5f942f6db9db9b0a9d8a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
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
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
/*  Copyright (C) 2022 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>

    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
    along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

#pragma once

#include "contrib/semaphore.h"
#include "knot/catalog/catalog_update.h"
#include "knot/conf/conf.h"
#include "knot/conf/confio.h"
#include "knot/journal/journal_basic.h"
#include "knot/journal/serialization.h"
#include "knot/events/events.h"
#include "knot/updates/changesets.h"
#include "knot/zone/contents.h"
#include "knot/zone/timers.h"
#include "libknot/dname.h"
#include "libknot/dynarray.h"
#include "libknot/packet/pkt.h"

struct zone_update;
struct zone_backup_ctx;

/*!
 * \brief Zone flags.
 *
 * When updating check create_zone_reload() if the flag mask is ok.
 */
typedef enum {
	ZONE_FORCE_AXFR     = 1 << 0, /*!< Force AXFR as next transfer. */
	ZONE_FORCE_RESIGN   = 1 << 1, /*!< Force zone re-sign. */
	ZONE_FORCE_FLUSH    = 1 << 2, /*!< Force zone flush. */
	ZONE_FORCE_KSK_ROLL = 1 << 3, /*!< Force KSK/CSK rollover. */
	ZONE_FORCE_ZSK_ROLL = 1 << 4, /*!< Force ZSK rollover. */
	ZONE_IS_CATALOG     = 1 << 5, /*!< This is a catalog. */
	ZONE_IS_CAT_MEMBER  = 1 << 6, /*!< This zone exists according to a catalog. */
	ZONE_XFR_FROZEN     = 1 << 7, /*!< Outgoing AXFR/IXFR temporarily disabled. */
	ZONE_USER_FLUSH     = 1 << 8, /*!< User-triggered flush. */
} zone_flag_t;

/*!
 * \brief Track unsuccessful NOTIFY targets.
 */
typedef uint64_t notifailed_rmt_hash;
knot_dynarray_declare(notifailed_rmt, notifailed_rmt_hash, DYNARRAY_VISIBILITY_NORMAL, 4);

/*!
 * \brief Zone purging parameter flags.
 */
typedef enum {
	PURGE_ZONE_BEST     = 1 << 0, /*!< Best effort -- continue on failures. */
	PURGE_ZONE_LOG      = 1 << 1, /*!< Log a purged zone even if requested less. */
	PURGE_ZONE_NOSYNC   = 1 << 2, /*!< Remove even zone files with disabled syncing. */
	PURGE_ZONE_TIMERS   = 1 << 3, /*!< Purge the zone timers. */
	PURGE_ZONE_ZONEFILE = 1 << 4, /*!< Purge the zone file. */
	PURGE_ZONE_JOURNAL  = 1 << 5, /*!< Purge the zone journal. */
	PURGE_ZONE_KASPDB   = 1 << 6, /*!< Purge KASP DB. */
	PURGE_ZONE_CATALOG  = 1 << 7, /*!< Purge the catalog. */
} purge_flag_t;

#define PURGE_ZONE_FULL       ~0U     /*!< Purge everything possible. */
                                      /*!< Standard purge (respect C_ZONEFILE_SYNC param). */
#define PURGE_ZONE_ALL        (PURGE_ZONE_FULL ^ PURGE_ZONE_NOSYNC)
                                      /*!< All data. */
#define PURGE_ZONE_DATA       (PURGE_ZONE_TIMERS | PURGE_ZONE_ZONEFILE | PURGE_ZONE_JOURNAL | \
                               PURGE_ZONE_KASPDB | PURGE_ZONE_CATALOG)

/*!
 * \brief Structure for holding DNS zone.
 */
typedef struct zone
{
	knot_dname_t *name;
	zone_contents_t *contents;
	zone_flag_t flags;
	bool is_catalog_flag; //!< Lock-less indication of ZONE_IS_CATALOG flag.

	/*! \brief Dynamic configuration zone change type. */
	conf_io_type_t change_type;

	/*! \brief Zonefile parameters. */
	struct {
		struct timespec mtime;
		uint32_t serial;
		bool exists;
		bool resigned;
		bool retransfer;
		uint8_t bootstrap_cnt; //!< Rebootstrap count (not related to zonefile).
	} zonefile;

	/*! \brief Zone events. */
	zone_timers_t timers;      //!< Persistent zone timers.
	zone_events_t events;      //!< Zone events timers.

	/*! \brief Track unsuccessful NOTIFY targets. */
	notifailed_rmt_dynarray_t notifailed;

	/*! \brief DDNS queue and lock. */
	pthread_mutex_t ddns_lock;
	size_t ddns_queue_size;
	list_t ddns_queue;

	/*! \brief Control update context. */
	struct zone_update *control_update;

	/*! \brief Ensue one COW transaction on zone's trees at a time. */
	knot_sem_t cow_lock;

	/*! \brief Pointer on running server with e.g. KASP db, journal DB, catalog... */
	struct server *server;

	/*! \brief Zone backup context (NULL unless backup pending). */
	struct zone_backup_ctx *backup_ctx;

	/*! \brief Catalog-generate feature. */
	knot_dname_t *catalog_gen;
	catalog_update_t *cat_members;
	const char *catalog_group;

	/*! \brief Preferred master lock. Also used for flags access. */
	pthread_mutex_t preferred_lock;
	/*! \brief Preferred master for remote operation. */
	struct sockaddr_storage *preferred_master;

	/*! \brief Query modules. */
	list_t query_modules;
	struct query_plan *query_plan;
} zone_t;

/*!
 * \brief Creates new zone with empty zone content.
 *
 * \param name  Zone name.
 *
 * \return The initialized zone structure or NULL if an error occurred.
 */
zone_t* zone_new(const knot_dname_t *name);

/*!
 * \brief Deallocates the zone structure.
 *
 * \note The function also deallocates all bound structures (contents, etc.).
 *
 * \param zone_ptr Zone to be freed.
 */
void zone_free(zone_t **zone_ptr);

/*!
 * \brief Clear zone contents (->SERVFAIL), reset modules, plan LOAD.
 *
 * \param conf   Current configuration.
 * \param zone   Zone to be re-set.
 */
void zone_reset(conf_t *conf, zone_t *zone);

/*!
 * \brief Purges selected zone components.
 *
 * \param conf    Current configuration.
 * \param zone    Zone to be purged.
 * \param params  Zone components to be purged and the purging mode
 *                (with PURGE_ZONE_BEST try to purge everything requested,
 *                otherwise exit on the first failure).
 *
 * \return        KNOT_E*
 */
int selective_zone_purge(conf_t *conf, zone_t *zone, purge_flag_t params);

/*!
 * \brief Clears possible control update transaction.
 *
 * \param zone Zone to be cleared.
 */
void zone_control_clear(zone_t *zone);

/*!
 * \brief Common database getters.
 */
knot_lmdb_db_t *zone_journaldb(const zone_t *zone);
knot_lmdb_db_t *zone_kaspdb(const zone_t *zone);
catalog_t *zone_catalog(const zone_t *zone);
catalog_update_t *zone_catalog_upd(const zone_t *zone);

/*!
 * \brief Only for RO journal operations.
 */
inline static zone_journal_t zone_journal(zone_t *zone)
{
	zone_journal_t j = { zone_journaldb(zone), zone->name, NULL };
	return j;
}

int zone_change_store(conf_t *conf, zone_t *zone, changeset_t *change, changeset_t *extra);
int zone_diff_store(conf_t *conf, zone_t *zone, const zone_diff_t *diff);
int zone_changes_clear(conf_t *conf, zone_t *zone);
int zone_in_journal_store(conf_t *conf, zone_t *zone, zone_contents_t *new_contents);

/*! \brief Synchronize zone file with journal. */
int zone_flush_journal(conf_t *conf, zone_t *zone, bool verbose);

bool zone_journal_has_zij(zone_t *zone);

/*!
 * \brief Clear failed_notify list before planning new NOTIFY.
 */
void zone_notifailed_clear(zone_t *zone);
void zone_schedule_notify(zone_t *zone, time_t delay);

/*!
 * \brief Atomically switch the content of the zone.
 */
zone_contents_t *zone_switch_contents(zone_t *zone, zone_contents_t *new_contents);

/*! \brief Checks if the zone is slave. */
bool zone_is_slave(conf_t *conf, const zone_t *zone);

/*! \brief Sets the address as a preferred master address. */
void zone_set_preferred_master(zone_t *zone, const struct sockaddr_storage *addr);

/*! \brief Clears the current preferred master address. */
void zone_clear_preferred_master(zone_t *zone);

/*! \brief Sets a zone flag. */
void zone_set_flag(zone_t *zone, zone_flag_t flag);

/*! \brief Unsets a zone flag. */
void zone_unset_flag(zone_t *zone, zone_flag_t flag);

/*! \brief Returns if a flag is set (and optionally clears it). */
zone_flag_t zone_get_flag(zone_t *zone, zone_flag_t flag, bool clear);

/*! \brief Get zone SOA RR. */
const knot_rdataset_t *zone_soa(const zone_t *zone);

/*! \brief Get zone SOA EXPIRE field, or 0 if empty zone. */
uint32_t zone_soa_expire(const zone_t *zone);

/*! \brief Check if zone is expired according to timers. */
bool zone_expired(const zone_t *zone);

/*!
 * \brief Set default timers for new zones or invalidate if not valid.
 */
void zone_timers_sanitize(conf_t *conf, zone_t *zone);

typedef struct {
	bool address; //!< Fallback to next remote address is required.
	bool remote;  //!< Fallback to next remote server is required.
} zone_master_fallback_t;

typedef int (*zone_master_cb)(conf_t *conf, zone_t *zone, const conf_remote_t *remote,
                              void *data, zone_master_fallback_t *fallback);

/*!
 * \brief Perform an action with all configured master servers.
 *
 * The function iterates over available masters. For each master, the callback
 * function is called once for its every adresses until the callback function
 * succeeds (\ref KNOT_EOK is returned) and then the iteration continues with
 * the next master.
 *
 * \return Error code from the last callback or KNOT_ENOMASTER.
 */
int zone_master_try(conf_t *conf, zone_t *zone, zone_master_cb callback,
                    void *callback_data, const char *err_str);

/*! \brief Write zone contents to zonefile, but into different directory. */
int zone_dump_to_dir(conf_t *conf, zone_t *zone, const char *dir);

int zone_set_master_serial(zone_t *zone, uint32_t serial);

int zone_get_master_serial(zone_t *zone, uint32_t *serial);

int zone_set_lastsigned_serial(zone_t *zone, uint32_t serial);

int zone_get_lastsigned_serial(zone_t *zone, uint32_t *serial);

int slave_zone_serial(zone_t *zone, conf_t *conf, uint32_t *serial);