1 /*------------------------------------------------------------------------------
2 *
3 * Copyright (c) 2011-2021, EURid vzw. All rights reserved.
4 * The YADIFA TM software product is provided under the BSD 3-clause license:
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * * Neither the name of EURid nor the names of its contributors may be
16 * used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 *
31 *------------------------------------------------------------------------------
32 *
33 */
34
35 /** @defgroup
36 * @ingroup
37 * @brief
38 *
39 *
40 *
41 * @{
42 *
43 *----------------------------------------------------------------------------*/
44 #include "dnsdb/dnsdb-config.h"
45 #include <ctype.h>
46 #include <dnscore/format.h>
47 #include <dnscore/fdtools.h>
48 #include <dnscore/serial.h>
49 #include <dnscore/timems.h>
50 #include "dnsdb/zdb-zone-path-provider.h"
51
52 static ya_result
53 zdb_zone_path_provider_default(const u8* domain_fqdn, char *path_buffer, u32 path_buffer_size, u32 flags);
54
55 static zdb_zone_path_provider_callback *zdb_zone_path_provider = zdb_zone_path_provider_default;
56 static char *xfr_path = LOCALSTATEDIR "/zones/xfr";
57 static bool xfr_path_free = FALSE;
58
59 /**
60 * The hash function that gives a number from an ASCIIZ string
61 *
62 * @param p ASCIIZ string
63 *
64 * @return the hash
65 */
66
67 static u32
zdb_zone_path_provider_copy_hash(const u8 * p)68 zdb_zone_path_provider_copy_hash(const u8 *p)
69 {
70 u32 h = 0;
71 u32 c;
72 u8 s = 0;
73 do
74 {
75 c = toupper(*p++);
76 c &= 0x3f;
77 h += c << (s & 15);
78 h += 97;
79 s += 13;
80 }
81 while(c != 0);
82
83 return h;
84 }
85
86 /**
87 *
88 * Returns the hashed folder path for a zone.
89 *
90 * @param data_path the target buffer for the data path
91 * @param data_path_size the target buffer size
92 * @param base_data_path the base folder
93 * @param origin the origin of the zone
94 *
95 * @return
96 */
97
98 static ya_result
zdb_zone_path_provider_get_data_path(char * data_path,u32 data_path_size,const char * base_data_path,const u8 * origin)99 zdb_zone_path_provider_get_data_path(char *data_path, u32 data_path_size, const char *base_data_path, const u8 *origin)
100 {
101 u32 h = zdb_zone_path_provider_copy_hash(origin);
102
103 return snformat(data_path, data_path_size, "%s/%02x/%02x", base_data_path, h & 0xff, (h >> 8) & 0xff);
104 }
105
106 /**
107 * For backward compatibility
108 *
109 * @param path
110 */
111
112 void
journal_set_xfr_path(const char * path)113 journal_set_xfr_path(const char *path)
114 {
115 if(xfr_path_free)
116 {
117 free((char*)xfr_path);
118 }
119
120 if(path == NULL)
121 {
122 xfr_path = LOCALSTATEDIR "/xfr";
123 xfr_path_free = FALSE;
124 }
125 else
126 {
127 xfr_path = strdup(path);
128 xfr_path_free = TRUE;
129 }
130 }
131
132 /**
133 * For backward compatibility
134 */
135
136 const char*
journal_get_xfr_path()137 journal_get_xfr_path()
138 {
139 return xfr_path;
140 }
141
142 static ya_result
zdb_zone_path_provider_default(const u8 * domain_fqdn,char * path_buffer,u32 path_buffer_size,u32 flags)143 zdb_zone_path_provider_default(const u8* domain_fqdn, char *path_buffer, u32 path_buffer_size, u32 flags)
144 {
145 ya_result ret;
146 char *suffix = "";
147 char dir_path[PATH_MAX];
148
149 if((flags & ZDB_ZONE_PATH_PROVIDER_RNDSUFFIX) != 0)
150 {
151 flags &= ~ZDB_ZONE_PATH_PROVIDER_RNDSUFFIX;
152 suffix = ".part";
153 }
154
155 if(FAIL(ret = zdb_zone_path_provider_get_data_path(dir_path, sizeof(dir_path), xfr_path, domain_fqdn))) // default path provider
156 {
157 return ret;
158 }
159
160 if((flags & ZDB_ZONE_PATH_PROVIDER_MKDIR) != 0)
161 {
162 flags &= ~ZDB_ZONE_PATH_PROVIDER_MKDIR;
163
164 if(FAIL(ret = mkdir_ex(dir_path, 0755, 0)))
165 {
166 return ret;
167 }
168 }
169
170 switch(flags)
171 {
172 case ZDB_ZONE_PATH_PROVIDER_ZONE_FILE:
173 {
174 ret = snformat(path_buffer, path_buffer_size, "%s/%{dnsname}%s", dir_path, domain_fqdn, suffix);
175 break;
176 }
177 case ZDB_ZONE_PATH_PROVIDER_ZONE_PATH:
178 {
179 ret = snformat(path_buffer, path_buffer_size, "%s", dir_path);
180 break;
181 }
182 case ZDB_ZONE_PATH_PROVIDER_DNSKEY_PATH:
183 {
184 ret = snformat(path_buffer, path_buffer_size, "%s/keys", dir_path);
185 break;
186 }
187 default:
188 {
189 ret = INVALID_ARGUMENT_ERROR; // no handled flags have been used
190 }
191 }
192
193 return ret;
194 }
195
196 /**
197 * Sets the provider.
198 * Note that the provider should return the length of the strings it returns.
199 *
200 * @param provider the provider or NULL to reset to the default one.
201 */
202
203 void
zdb_zone_path_set_provider(zdb_zone_path_provider_callback * provider)204 zdb_zone_path_set_provider(zdb_zone_path_provider_callback *provider)
205 {
206 if(provider == NULL)
207 {
208 provider = zdb_zone_path_provider_default;
209 }
210
211 zdb_zone_path_provider = provider;
212 }
213
214 /**
215 *
216 * @return
217 */
218
219 static ya_result zdb_zone_info_provider_data_default(const u8 *origin, zdb_zone_info_provider_data *data, u32 flags);
220
221 static zdb_zone_info_provider_callback *zdb_zone_info_provider = zdb_zone_info_provider_data_default;
222
zdb_zone_info_provider_data_default(const u8 * origin,zdb_zone_info_provider_data * data,u32 flags)223 static ya_result zdb_zone_info_provider_data_default(const u8 *origin, zdb_zone_info_provider_data *data, u32 flags)
224 {
225 (void)origin;
226 (void)data;
227 (void)flags;
228
229 return FEATURE_NOT_IMPLEMENTED_ERROR;
230 }
231
232 zdb_zone_path_provider_callback *
zdb_zone_path_get_provider()233 zdb_zone_path_get_provider()
234 {
235 return zdb_zone_path_provider;
236 }
237
238 void
zdb_zone_info_set_provider(zdb_zone_info_provider_callback * data)239 zdb_zone_info_set_provider(zdb_zone_info_provider_callback *data)
240 {
241 if(data == NULL)
242 {
243 data = zdb_zone_info_provider_data_default;
244 }
245
246 zdb_zone_info_provider = data;
247 }
248
249 zdb_zone_info_provider_callback *
zdb_zone_info_get_provider()250 zdb_zone_info_get_provider()
251 {
252 return zdb_zone_info_provider;
253 }
254
255 ya_result
zdb_zone_info_get_stored_serial(const u8 * origin,u32 * serial)256 zdb_zone_info_get_stored_serial(const u8 *origin, u32 *serial)
257 {
258 yassert(origin != NULL);
259 yassert(serial != NULL);
260 zdb_zone_info_provider_data data;
261 ya_result ret;
262 if(ISOK(ret = zdb_zone_info_get_provider()(origin, &data, ZDB_ZONE_INFO_PROVIDER_STORED_SERIAL)))
263 {
264 *serial = data._u32; // VS false positive: reaching this point, data is initialized (by contract)
265 }
266 return ret;
267 }
268
269 ya_result
zdb_zone_info_get_zone_max_journal_size(const u8 * origin,u32 * size)270 zdb_zone_info_get_zone_max_journal_size(const u8 *origin, u32 *size)
271 {
272 yassert(origin != NULL);
273 yassert(size != NULL);
274 zdb_zone_info_provider_data data;
275 data._u64 = *size; // known wire size / 2
276 ya_result ret;
277 if(ISOK(ret = zdb_zone_info_get_provider()(origin, &data, ZDB_ZONE_INFO_PROVIDER_MAX_JOURNAL_SIZE)))
278 {
279 if(data._u64 > MAX_U32)
280 {
281 data._u64 = MAX_U32;
282 }
283
284 /// @note THX: here, if data._u64 is < 256*1024, then set to 256*1024 .
285
286 *size = data._u64;
287 }
288 return ret;
289 }
290
291 ya_result
zdb_zone_info_get_zone_type(const u8 * origin,u8 * zt)292 zdb_zone_info_get_zone_type(const u8 *origin, u8 *zt)
293 {
294 yassert(origin != NULL);
295 yassert(zt != NULL);
296 zdb_zone_info_provider_data data;
297 ya_result ret;
298 if(ISOK(ret = zdb_zone_info_get_provider()(origin, &data, ZDB_ZONE_INFO_PROVIDER_ZONE_TYPE)))
299 {
300 *zt = data._u8; // VS false positive: reaching this point, data is initialized (by contract)
301 }
302 return ret;
303 }
304
305 ya_result
zdb_zone_info_background_store_zone(const u8 * origin)306 zdb_zone_info_background_store_zone(const u8 *origin)
307 {
308 yassert(origin != NULL);
309 ya_result ret;
310
311 ret = zdb_zone_info_get_provider()(origin, NULL, ZDB_ZONE_INFO_PROVIDER_STORE_TRIGGER);
312
313 return ret;
314 }
315
316 ya_result
zdb_zone_info_store_locked_zone(const u8 * origin)317 zdb_zone_info_store_locked_zone(const u8 *origin)
318 {
319 yassert(origin != NULL);
320 ya_result ret;
321
322 zdb_zone_info_provider_data already_locked_by;
323 already_locked_by._u8 = 0;
324 ret = zdb_zone_info_get_provider()(origin, &already_locked_by, ZDB_ZONE_INFO_PROVIDER_STORE_NOW);
325
326 return ret;
327 }
328
329 /**
330 *
331 * Should not be used anymore.
332 *
333 * @param origin
334 * @param minimum_serial
335 * @return
336 */
337
338 ya_result
zdb_zone_info_background_store_zone_and_wait_for_serial(const u8 * origin,u32 minimum_serial)339 zdb_zone_info_background_store_zone_and_wait_for_serial(const u8 *origin, u32 minimum_serial)
340 {
341 // This mechanism should be improved : the zone should be unlocked, frozen, saved, unfrozen, re-locked
342
343 yassert(origin != NULL);
344 ya_result ret;
345
346 ret = zdb_zone_info_get_provider()(origin, NULL, ZDB_ZONE_INFO_PROVIDER_STORE_TRIGGER);
347
348 if(ISOK(ret))
349 {
350 u64 start = timeus();
351
352 for(;;)
353 {
354 u32 serial;
355 if(FAIL(ret = zdb_zone_info_get_stored_serial(origin, &serial)))
356 {
357 return ret;
358 }
359 if(serial_ge(serial, minimum_serial))
360 {
361 return SUCCESS;
362 }
363
364 u64 now = timeus();
365
366 if(now < start)
367 {
368 start = now; //clock modified
369 }
370
371 if(now - start > ONE_SECOND_US)
372 {
373 zdb_zone_info_provider_data already_locked_by;
374
375 already_locked_by._u8 = 0;
376
377 if(FAIL(ret = zdb_zone_info_get_provider()(origin, &already_locked_by, ZDB_ZONE_INFO_PROVIDER_STORE_TRIGGER)))
378 {
379 return ret;
380 }
381 }
382
383 usleep(500000);
384 }
385 }
386
387 return ret;
388 }
389
390 ya_result
zdb_zone_info_background_store_in_progress(const u8 * origin)391 zdb_zone_info_background_store_in_progress(const u8 *origin)
392 {
393 // This mechanism should be improved : the zone should be unlocked, frozen, saved, unfrozen, re-locked
394
395 yassert(origin != NULL);
396 ya_result ret;
397
398 ret = zdb_zone_info_get_provider()(origin, NULL, ZDB_ZONE_INFO_PROVIDER_STORE_IN_PROGRESS);
399
400 return ret;
401 }
402
403 /** @} */
404