1 /*
2  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3  *
4  * SPDX-License-Identifier: MPL-2.0
5  *
6  * This Source Code Form is subject to the terms of the Mozilla Public
7  * License, v. 2.0. If a copy of the MPL was not distributed with this
8  * file, you can obtain one at https://mozilla.org/MPL/2.0/.
9  *
10  * See the COPYRIGHT file distributed with this work for additional
11  * information regarding copyright ownership.
12  */
13 
14 #ifndef DNS_JOURNAL_H
15 #define DNS_JOURNAL_H 1
16 
17 /*****
18 ***** Module Info
19 *****/
20 
21 /*! \file dns/journal.h
22  * \brief
23  * Database journaling.
24  */
25 
26 /***
27  *** Imports
28  ***/
29 
30 #include <inttypes.h>
31 #include <stdbool.h>
32 
33 #include <isc/lang.h>
34 #include <isc/magic.h>
35 
36 #include <dns/diff.h>
37 #include <dns/name.h>
38 #include <dns/rdata.h>
39 #include <dns/types.h>
40 
41 /***
42  *** Defines.
43  ***/
44 #define DNS_JOURNALOPT_RESIGN 0x00000001
45 
46 #define DNS_JOURNAL_READ   0x00000000 /* false */
47 #define DNS_JOURNAL_CREATE 0x00000001 /* true */
48 #define DNS_JOURNAL_WRITE  0x00000002
49 
50 #define DNS_JOURNAL_SIZE_MAX INT32_MAX
51 #define DNS_JOURNAL_SIZE_MIN 4096
52 
53 /*% Print transaction header data */
54 #define DNS_JOURNAL_PRINTXHDR 0x0001
55 
56 /*% Rewrite whole journal file instead of compacting */
57 #define DNS_JOURNAL_COMPACTALL 0x0001
58 #define DNS_JOURNAL_VERSION1   0x0002
59 
60 /***
61  *** Types
62  ***/
63 
64 /*%
65  * A dns_journal_t represents an open journal file.  This is an opaque type.
66  *
67  * A particular dns_journal_t object may be opened for writing, in which case
68  * it can be used for writing transactions to a journal file, or it can be
69  * opened for reading, in which case it can be used for reading transactions
70  * from (iterating over) a journal file.  A single dns_journal_t object may
71  * not be used for both purposes.
72  */
73 typedef struct dns_journal dns_journal_t;
74 
75 /***
76  *** Functions
77  ***/
78 
79 ISC_LANG_BEGINDECLS
80 
81 /**************************************************************************/
82 
83 isc_result_t
84 dns_db_createsoatuple(dns_db_t *db, dns_dbversion_t *ver, isc_mem_t *mctx,
85 		      dns_diffop_t op, dns_difftuple_t **tp);
86 /*!< brief
87  * Create a diff tuple for the current database SOA.
88  * XXX this probably belongs somewhere else.
89  */
90 
91 /*@{*/
92 #define DNS_SERIAL_GT(a, b) ((int)(((a) - (b)) & 0xFFFFFFFF) > 0)
93 #define DNS_SERIAL_GE(a, b) ((int)(((a) - (b)) & 0xFFFFFFFF) >= 0)
94 /*!< brief
95  * Compare SOA serial numbers.  DNS_SERIAL_GT(a, b) returns true iff
96  * a is "greater than" b where "greater than" is as defined in RFC1982.
97  * DNS_SERIAL_GE(a, b) returns true iff a is "greater than or equal to" b.
98  */
99 /*@}*/
100 
101 /**************************************************************************/
102 /*
103  * Journal object creation and destruction.
104  */
105 
106 isc_result_t
107 dns_journal_open(isc_mem_t *mctx, const char *filename, unsigned int mode,
108 		 dns_journal_t **journalp);
109 /*%<
110  * Open the journal file 'filename' and create a dns_journal_t object for it.
111  *
112  * DNS_JOURNAL_CREATE open the journal for reading and writing and create
113  * the journal if it does not exist.
114  * DNS_JOURNAL_WRITE open the journal for reading and writing.
115  * DNS_JOURNAL_READ open the journal for reading only.
116  */
117 
118 void
119 dns_journal_destroy(dns_journal_t **journalp);
120 /*%<
121  * Destroy a dns_journal_t, closing any open files and freeing its memory.
122  */
123 
124 /**************************************************************************/
125 /*
126  * Writing transactions to journals.
127  */
128 
129 isc_result_t
130 dns_journal_begin_transaction(dns_journal_t *j);
131 /*%<
132  * Prepare to write a new transaction to the open journal file 'j'.
133  *
134  * Requires:
135  *     \li 'j' is open for writing.
136  */
137 
138 isc_result_t
139 dns_journal_writediff(dns_journal_t *j, dns_diff_t *diff);
140 /*%<
141  * Write 'diff' to the current transaction of journal file 'j'.
142  *
143  * Requires:
144  * \li     'j' is open for writing and dns_journal_begin_transaction()
145  * 	has been called.
146  *
147  *\li 	'diff' is a full or partial, correctly ordered IXFR
148  *      difference sequence.
149  */
150 
151 isc_result_t
152 dns_journal_commit(dns_journal_t *j);
153 /*%<
154  * Commit the current transaction of journal file 'j'.
155  *
156  * Requires:
157  * \li     'j' is open for writing and dns_journal_begin_transaction()
158  * 	has been called.
159  *
160  *   \li   dns_journal_writediff() has been called one or more times
161  * 	to form a complete, correctly ordered IXFR difference
162  *      sequence.
163  */
164 
165 isc_result_t
166 dns_journal_write_transaction(dns_journal_t *j, dns_diff_t *diff);
167 /*%
168  * Write a complete transaction at once to a journal file,
169  * sorting it if necessary, and commit it.  Equivalent to calling
170  * dns_diff_sort(), dns_journal_begin_transaction(),
171  * dns_journal_writediff(), and dns_journal_commit().
172  *
173  * Requires:
174  *\li      'j' is open for writing.
175  *
176  * \li	'diff' contains exactly one SOA deletion, one SOA addition
177  *       with a greater serial number, and possibly other changes,
178  *       in arbitrary order.
179  */
180 
181 /**************************************************************************/
182 /*
183  * Reading transactions from journals.
184  */
185 
186 bool
187 dns_journal_empty(dns_journal_t *j);
188 /*<
189  * Find out if a journal is empty.
190  */
191 
192 bool
193 dns_journal_recovered(dns_journal_t *j);
194 /*<
195  * Find out if the journal could be opened using old journal format
196  */
197 
198 uint32_t
199 dns_journal_first_serial(dns_journal_t *j);
200 uint32_t
201 dns_journal_last_serial(dns_journal_t *j);
202 /*%<
203  * Get the first and last addressable serial number in the journal.
204  */
205 
206 isc_result_t
207 dns_journal_iter_init(dns_journal_t *j, uint32_t begin_serial,
208 		      uint32_t end_serial, size_t *xfrsizep);
209 /*%<
210  * Prepare to iterate over the transactions that will bring the database
211  * from SOA serial number 'begin_serial' to 'end_serial'.
212  *
213  * If 'xfrsizep' is not NULL, then on success it will be set to the
214  * total size of all records in the iteration (excluding headers). This
215  * is meant to be a rough approximation of the size of an incremental
216  * zone transfer, though it does not account for DNS message overhead
217  * or name compression.)
218  *
219  * Returns:
220  *\li	ISC_R_SUCCESS
221  *\li	ISC_R_RANGE	begin_serial is outside the addressable range.
222  *\li	ISC_R_NOTFOUND	begin_serial is within the range of addressable
223  *			serial numbers covered by the journal, but
224  *			this particular serial number does not exist.
225  */
226 
227 /*@{*/
228 isc_result_t
229 dns_journal_first_rr(dns_journal_t *j);
230 isc_result_t
231 dns_journal_next_rr(dns_journal_t *j);
232 /*%<
233  * Position the iterator at the first/next RR in a journal
234  * transaction sequence established using dns_journal_iter_init().
235  *
236  * Requires:
237  *    \li  dns_journal_iter_init() has been called.
238  *
239  */
240 /*@}*/
241 
242 void
243 dns_journal_current_rr(dns_journal_t *j, dns_name_t **name, uint32_t *ttl,
244 		       dns_rdata_t **rdata);
245 /*%<
246  * Get the name, ttl, and rdata of the current journal RR.
247  *
248  * Requires:
249  * \li     The last call to dns_journal_first_rr() or dns_journal_next_rr()
250  *      returned ISC_R_SUCCESS.
251  */
252 
253 /**************************************************************************/
254 /*
255  * Database roll-forward.
256  */
257 
258 isc_result_t
259 dns_journal_rollforward(dns_journal_t *j, dns_db_t *db, unsigned int options);
260 /*%<
261  * Roll forward (play back) the journal file "filename" into the
262  * database "db".  This should be called when the server starts
263  * after a shutdown or crash.
264  *
265  * Requires:
266  *\li   'journal' is a valid journal
267  *\li	'db' is a valid database which does not have a version
268  *           open for writing.
269  *
270  * Returns:
271  *\li	ISC_R_NOTFOUND when current serial in not in journal.
272  *\li	ISC_R_RANGE when current serial in not in journals range.
273  *\li	DNS_R_UPTODATE when the database was already up to date.
274  *\li	ISC_R_SUCCESS journal has been applied successfully to the
275  *      database without any issues.
276  *
277  *	others
278  */
279 
280 isc_result_t
281 dns_journal_print(isc_mem_t *mctx, uint32_t flags, const char *filename,
282 		  FILE *file);
283 /* For debugging not general use */
284 
285 isc_result_t
286 dns_db_diff(isc_mem_t *mctx, dns_db_t *dba, dns_dbversion_t *dbvera,
287 	    dns_db_t *dbb, dns_dbversion_t *dbverb,
288 	    const char *journal_filename);
289 
290 isc_result_t
291 dns_db_diffx(dns_diff_t *diff, dns_db_t *dba, dns_dbversion_t *dbvera,
292 	     dns_db_t *dbb, dns_dbversion_t *dbverb,
293 	     const char *journal_filename);
294 /*%<
295  * Compare the databases 'dba' and 'dbb' and generate a diff/journal
296  * entry containing the changes to make 'dba' from 'dbb' (note
297  * the order).  This journal entry will consist of a single,
298  * possibly very large transaction.  Append the journal
299  * entry to the journal file specified by 'journal_filename' if
300  * non-NULL.
301  */
302 
303 isc_result_t
304 dns_journal_compact(isc_mem_t *mctx, char *filename, uint32_t serial,
305 		    uint32_t flags, uint32_t target_size);
306 /*%<
307  * Attempt to compact the journal if it is greater that 'target_size'.
308  * Changes from 'serial' onwards will be preserved. Changes prior than
309  * that may be dropped in order to get the journal below `target_size`.
310  *
311  * If 'flags' includes DNS_JOURNAL_COMPACTALL, the entire journal is copied.
312  * In this case, `serial` is ignored. This flag is used when upgrading or
313  * downgrading the format version of the journal. If 'flags' also includes
314  * DNS_JOURNAL_VERSION1, then the journal is copied out in the original
315  * format used prior to BIND 9.16.12; otherwise it is copied in the
316  * current format.
317  *
318  * If _COMPACTALL is not in use, and the journal file exists and is
319  * non-empty, then 'serial' must exist in the journal.
320  *
321  * Returns:
322  *\li	ISC_R_SUCCESS
323  *\li	ISC_R_RANGE	serial is outside the range existing in the journal
324  *
325  * Other errors may be returned from file operations.
326  */
327 
328 bool
329 dns_journal_get_sourceserial(dns_journal_t *j, uint32_t *sourceserial);
330 void
331 dns_journal_set_sourceserial(dns_journal_t *j, uint32_t sourceserial);
332 /*%<
333  * Get and set source serial.
334  *
335  * Returns:
336  *      true if sourceserial has previously been set.
337  */
338 
339 ISC_LANG_ENDDECLS
340 
341 #endif /* DNS_JOURNAL_H */
342