1 /*
2 * Copyright (c) 2009 NLNet Labs. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
17 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
19 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
21 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
22 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
23 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 *
25 */
26
27 /**
28 * IXFR Journal.
29 *
30 */
31
32 #include "config.h"
33 #include "util.h"
34 #include "signer/ixfr.h"
35 #include "signer/rrset.h"
36 #include "signer/zone.h"
37
38 static const char* ixfr_str = "journal";
39
40
41 /**
42 * Create a part of ixfr journal.
43 *
44 */
45 static part_type*
part_create()46 part_create()
47 {
48 part_type* part = NULL;
49
50 CHECKALLOC(part = (part_type*) malloc(sizeof(part_type)));
51 part->soaplus = NULL;
52 part->soamin = NULL;
53 part->plus = ldns_rr_list_new();
54 if (!part->plus) {
55 ods_log_error("[%s] unable to create ixfr part: "
56 "ldns_rr_list_new() failed", ixfr_str);
57 free(part);
58 return NULL;
59 }
60 part->min = ldns_rr_list_new();
61 if (!part->min) {
62 ods_log_error("[%s] unable to create ixfr part: "
63 "ldns_rr_list_new() failed", ixfr_str);
64 ldns_rr_list_free(part->plus);
65 free(part);
66 return NULL;
67 }
68 return part;
69 }
70
71
72 /**
73 * Clean up a part of ixfr journal and free it.
74 *
75 */
76 static void
part_free(part_type * part)77 part_free(part_type* part)
78 {
79 if (!part) return;
80 ldns_rr_list_deep_free(part->min);
81 ldns_rr_list_deep_free(part->plus);
82 free(part);
83 }
84
85
86 /**
87 * Create a new ixfr journal.
88 *
89 */
90 ixfr_type*
ixfr_create()91 ixfr_create()
92 {
93 size_t i = 0;
94 ixfr_type* xfr;
95
96 CHECKALLOC(xfr = (ixfr_type*) calloc(1, sizeof(ixfr_type)));
97 pthread_mutex_init(&xfr->ixfr_lock, NULL);
98 return xfr;
99 }
100
101
102 /**
103 * Add +RR to ixfr journal.
104 *
105 */
106 void
ixfr_add_rr(ixfr_type * ixfr,ldns_rr * rr)107 ixfr_add_rr(ixfr_type* ixfr, ldns_rr* rr)
108 {
109 ldns_rr* rr_copy = ldns_rr_clone(rr);
110
111 ods_log_assert(ixfr)
112 ods_log_assert(rr);
113 ods_log_assert(ixfr->part[0]);
114 ods_log_assert(ixfr->part[0]->plus);
115
116 if (!ldns_rr_list_push_rr(ixfr->part[0]->plus, rr_copy)) {
117 ldns_rr_free(rr_copy);
118 ods_fatal_exit("[%s] fatal unable to +RR: ldns_rr_list_push_rr() failed",
119 ixfr_str);
120 }
121 if (ldns_rr_get_type(rr_copy) == LDNS_RR_TYPE_SOA) {
122 ixfr->part[0]->soaplus = rr_copy;
123 }
124 }
125
126
127 /**
128 * Add -RR to ixfr journal.
129 *
130 */
131 void
ixfr_del_rr(ixfr_type * ixfr,ldns_rr * rr)132 ixfr_del_rr(ixfr_type* ixfr, ldns_rr* rr)
133 {
134 ldns_rr* rr_copy = ldns_rr_clone(rr);
135
136 ods_log_assert(ixfr)
137 ods_log_assert(rr);
138 ods_log_assert(ixfr->part[0]);
139 ods_log_assert(ixfr->part[0]->min);
140
141 if (!ldns_rr_list_push_rr(ixfr->part[0]->min, rr_copy)) {
142 ldns_rr_free(rr_copy);
143 ods_fatal_exit("[%s] fatal unable to -RR: ldns_rr_list_push_rr() failed",
144 ixfr_str);
145 }
146 if (ldns_rr_get_type(rr_copy) == LDNS_RR_TYPE_SOA) {
147 ixfr->part[0]->soamin = rr_copy;
148 }
149 }
150
151
152 /**
153 * Print all RRs in list, except SOA RRs.
154 *
155 */
156 static int
part_rr_list_print_nonsoa(FILE * fd,ldns_rr_list * list)157 part_rr_list_print_nonsoa(FILE* fd, ldns_rr_list* list)
158 {
159 size_t i = 0;
160 int error = 0;
161 if (!list || !fd) {
162 return 1;
163 }
164 for (i = 0; i < ldns_rr_list_rr_count(list); i++) {
165 if (ldns_rr_get_type(ldns_rr_list_rr(list, i)) != LDNS_RR_TYPE_SOA) {
166 if (util_rr_print(fd, ldns_rr_list_rr(list, i)) != ODS_STATUS_OK) {
167 error = 1;
168 }
169 }
170 }
171 return error;
172 }
173
174
175 /**
176 * Print part of the ixfr journal.
177 *
178 */
179 static int
part_print(FILE * fd,ixfr_type * ixfr,size_t i)180 part_print(FILE* fd, ixfr_type* ixfr, size_t i)
181 {
182 part_type* part = NULL;
183 int error = 0;
184
185 ods_log_assert(ixfr);
186 ods_log_assert(fd);
187
188 part = ixfr->part[i];
189 if (!part || !part->soamin || !part->soaplus) {
190 return 0; /* due to code buggyness this is not considered an
191 error condition*/
192 }
193 ods_log_assert(part->min);
194 ods_log_assert(part->plus);
195 ods_log_assert(part->soamin);
196 ods_log_assert(part->soaplus);
197
198 if (util_rr_print(fd, part->soamin) != ODS_STATUS_OK) {
199 return 1;
200 } else if (part_rr_list_print_nonsoa(fd, part->min)) {
201 return 1;
202 } else if (util_rr_print(fd, part->soaplus) != ODS_STATUS_OK) {
203 return 1;
204 } else if (part_rr_list_print_nonsoa(fd, part->plus)) {
205 return 1;
206 }
207 return 0;
208 }
209
210
211 /**
212 * Print the ixfr journal.
213 *
214 */
215 int
ixfr_print(FILE * fd,ixfr_type * ixfr)216 ixfr_print(FILE* fd, ixfr_type* ixfr)
217 {
218 int i = 0, error = 0;
219
220 ods_log_assert(fd);
221 ods_log_assert(ixfr);
222
223 ods_log_debug("[%s] print ixfr", ixfr_str);
224 for (i = IXFR_MAX_PARTS - 1; i >= 0; i--) {
225 ods_log_deeebug("[%s] print ixfr part #%d", ixfr_str, i);
226 if (part_print(fd, ixfr, i)) {
227 return 1;
228 }
229 }
230 return 0;
231 }
232
233
234 /**
235 * Purge the ixfr journal.
236 *
237 */
238 void
ixfr_purge(ixfr_type * ixfr,char const * zonename)239 ixfr_purge(ixfr_type* ixfr, char const *zonename)
240 {
241 int i = 0;
242
243 ods_log_assert(ixfr);
244 ods_log_assert(zonename);
245
246 if (ixfr->part[0] &&
247 (!ixfr->part[0]->soamin || !ixfr->part[0]->soaplus))
248 {
249 /* Somehow the signer does a double purge without having used
250 * this part. There is no need to create a new one. In fact,
251 * we should not. It would cause an assertion later on when
252 * printing to file */
253 return;
254 }
255
256 ods_log_debug("[%s] purge ixfr for zone %s", ixfr_str, zonename);
257 for (i = IXFR_MAX_PARTS - 1; i >= 0; i--) {
258 if (i == (IXFR_MAX_PARTS - 1)) {
259 part_free(ixfr->part[i]);
260 ixfr->part[i] = NULL;
261 } else {
262 ixfr->part[i+1] = ixfr->part[i];
263 ixfr->part[i] = NULL;
264 }
265 }
266 ixfr->part[0] = part_create();
267 if (!ixfr->part[0]) {
268 ods_fatal_exit("[%s] fatal unable to purge ixfr for zone %s: "
269 "part_create() failed", ixfr_str, zonename);
270 }
271 }
272
273
274 /**
275 * Cleanup the ixfr journal.
276 *
277 */
278 void
ixfr_cleanup(ixfr_type * ixfr)279 ixfr_cleanup(ixfr_type* ixfr)
280 {
281 int i = 0;
282 if (!ixfr) {
283 return;
284 }
285 for (i = IXFR_MAX_PARTS - 1; i >= 0; i--) {
286 part_free(ixfr->part[i]);
287 }
288 pthread_mutex_destroy(&ixfr->ixfr_lock);
289 free(ixfr);
290 }
291