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