1 /*
2 * udbzone -- store zone and rrset information in udb file.
3 *
4 * Copyright (c) 2011, NLnet Labs. See LICENSE for license.
5 */
6 #include "config.h"
7 #include "udbzone.h"
8 #include "util.h"
9 #include "iterated_hash.h"
10 #include "dns.h"
11 #include "dname.h"
12 #include "difffile.h"
13 #include <string.h>
14
15 /** delete the zone plain its own data */
16 static void
udb_zone_delete_plain(udb_base * udb,udb_ptr * zone)17 udb_zone_delete_plain(udb_base* udb, udb_ptr* zone)
18 {
19 udb_ptr dtree;
20 assert(udb_ptr_get_type(zone) == udb_chunk_type_zone);
21 udb_zone_clear(udb, zone);
22 udb_rptr_zero(&ZONE(zone)->node, udb);
23 udb_rptr_zero(&ZONE(zone)->nsec3param, udb);
24 udb_rptr_zero(&ZONE(zone)->log_str, udb);
25 udb_rptr_zero(&ZONE(zone)->file_str, udb);
26 udb_ptr_new(&dtree, udb, &ZONE(zone)->domains);
27 udb_rptr_zero(&ZONE(zone)->domains, udb);
28 udb_radix_tree_delete(udb, &dtree);
29 udb_ptr_free_space(zone, udb,
30 sizeof(struct zone_d)+ZONE(zone)->namelen);
31 }
32
33 int
udb_dns_init_file(udb_base * udb)34 udb_dns_init_file(udb_base* udb)
35 {
36 udb_ptr ztree;
37 if(!udb_radix_tree_create(udb, &ztree)) {
38 return 0;
39 }
40 udb_base_set_userdata(udb, ztree.data);
41 udb_ptr_unlink(&ztree, udb);
42 return 1;
43 }
44
45 void
udb_dns_deinit_file(udb_base * udb)46 udb_dns_deinit_file(udb_base* udb)
47 {
48 udb_ptr ztree;
49 udb_ptr z;
50 udb_ptr_new(&ztree, udb, udb_base_get_userdata(udb));
51 if(udb_ptr_is_null(&ztree)) {
52 return;
53 }
54 assert(udb_ptr_get_type(&ztree) == udb_chunk_type_radtree);
55 /* delete all zones */
56 for(udb_radix_first(udb, &ztree, &z); z.data; udb_radix_next(udb, &z)){
57 udb_ptr zone;
58 udb_ptr_new(&zone, udb, &RADNODE(&z)->elem);
59 udb_rptr_zero(&RADNODE(&z)->elem, udb);
60 udb_zone_delete_plain(udb, &zone);
61 }
62 udb_ptr_unlink(&z, udb);
63
64 udb_base_set_userdata(udb, 0);
65 udb_radix_tree_delete(udb, &ztree);
66 }
67
68 int
udb_zone_create(udb_base * udb,udb_ptr * result,const uint8_t * dname,size_t dlen)69 udb_zone_create(udb_base* udb, udb_ptr* result, const uint8_t* dname,
70 size_t dlen)
71 {
72 udb_ptr ztree, z, node, dtree;
73 udb_ptr_new(&ztree, udb, udb_base_get_userdata(udb));
74 assert(udb_ptr_get_type(&ztree) == udb_chunk_type_radtree);
75 udb_ptr_init(result, udb);
76 if(udb_zone_search(udb, &z, dname, dlen)) {
77 udb_ptr_unlink(&ztree, udb);
78 udb_ptr_unlink(&z, udb);
79 /* duplicate */
80 return 0;
81 }
82 if(!udb_ptr_alloc_space(&z, udb, udb_chunk_type_zone,
83 sizeof(struct zone_d)+dlen)) {
84 udb_ptr_unlink(&ztree, udb);
85 /* failed alloc */
86 return 0;
87 }
88 /* init the zone object */
89 udb_rel_ptr_init(&ZONE(&z)->node);
90 udb_rel_ptr_init(&ZONE(&z)->domains);
91 udb_rel_ptr_init(&ZONE(&z)->nsec3param);
92 udb_rel_ptr_init(&ZONE(&z)->log_str);
93 udb_rel_ptr_init(&ZONE(&z)->file_str);
94 ZONE(&z)->rrset_count = 0;
95 ZONE(&z)->rr_count = 0;
96 ZONE(&z)->expired = 0;
97 ZONE(&z)->mtime = 0;
98 ZONE(&z)->mtime_nsec = 0;
99 ZONE(&z)->namelen = dlen;
100 memmove(ZONE(&z)->name, dname, dlen);
101 if(!udb_radix_tree_create(udb, &dtree)) {
102 udb_ptr_free_space(&z, udb, sizeof(struct zone_d)+dlen);
103 udb_ptr_unlink(&ztree, udb);
104 /* failed alloc */
105 return 0;
106 }
107 udb_rptr_set_ptr(&ZONE(&z)->domains, udb, &dtree);
108
109 /* insert it */
110 if(!udb_radname_insert(udb, &ztree, dname, dlen, &z, &node)) {
111 udb_ptr_free_space(&z, udb, sizeof(struct zone_d)+dlen);
112 udb_ptr_unlink(&ztree, udb);
113 udb_radix_tree_delete(udb, &dtree);
114 udb_ptr_unlink(&dtree, udb);
115 /* failed alloc */
116 return 0;
117 }
118 udb_rptr_set_ptr(&ZONE(&z)->node, udb, &node);
119 udb_ptr_set_ptr(result, udb, &z);
120 udb_ptr_unlink(&z, udb);
121 udb_ptr_unlink(&dtree, udb);
122 udb_ptr_unlink(&ztree, udb);
123 udb_ptr_unlink(&node, udb);
124 return 1;
125 }
126
127 /** delete an RR */
128 static void
rr_delete(udb_base * udb,udb_ptr * rr)129 rr_delete(udb_base* udb, udb_ptr* rr)
130 {
131 assert(udb_ptr_get_type(rr) == udb_chunk_type_rr);
132 udb_rptr_zero(&RR(rr)->next, udb);
133 udb_ptr_free_space(rr, udb, sizeof(struct rr_d)+RR(rr)->len);
134 }
135
136 /** delete an rrset */
137 static void
rrset_delete(udb_base * udb,udb_ptr * rrset)138 rrset_delete(udb_base* udb, udb_ptr* rrset)
139 {
140 udb_ptr rr, n;
141 assert(udb_ptr_get_type(rrset) == udb_chunk_type_rrset);
142
143 /* free RRs */
144 udb_ptr_new(&rr, udb, &RRSET(rrset)->rrs);
145 udb_ptr_init(&n, udb);
146 udb_rptr_zero(&RRSET(rrset)->rrs, udb);
147 while(!udb_ptr_is_null(&rr)) {
148 udb_ptr_set_rptr(&n, udb, &RR(&rr)->next);
149 rr_delete(udb, &rr);
150 udb_ptr_set_ptr(&rr, udb, &n);
151 udb_ptr_zero(&n, udb);
152 }
153 udb_ptr_unlink(&n, udb);
154 udb_ptr_unlink(&rr, udb);
155
156 udb_rptr_zero(&RRSET(rrset)->next, udb);
157 udb_ptr_free_space(rrset, udb, sizeof(struct rrset_d));
158 }
159
160 /** clear a domain of its rrsets, rrs */
161 static void
domain_clear(udb_base * udb,udb_ptr * d)162 domain_clear(udb_base* udb, udb_ptr* d)
163 {
164 udb_ptr rrset, n;
165 assert(udb_ptr_get_type(d) == udb_chunk_type_domain);
166 udb_ptr_new(&rrset, udb, &DOMAIN(d)->rrsets);
167 udb_ptr_init(&n, udb);
168 udb_rptr_zero(&DOMAIN(d)->rrsets, udb);
169 while(!udb_ptr_is_null(&rrset)) {
170 udb_ptr_set_rptr(&n, udb, &RRSET(&rrset)->next);
171 rrset_delete(udb, &rrset);
172 udb_ptr_set_ptr(&rrset, udb, &n);
173 udb_ptr_zero(&n, udb);
174 }
175 udb_ptr_unlink(&n, udb);
176 udb_ptr_unlink(&rrset, udb);
177 }
178
179 /** delete a domain and all its rrsets, rrs */
180 static void
domain_delete(udb_base * udb,udb_ptr * d)181 domain_delete(udb_base* udb, udb_ptr* d)
182 {
183 domain_clear(udb, d);
184 udb_rptr_zero(&DOMAIN(d)->node, udb);
185 udb_ptr_free_space(d, udb,
186 sizeof(struct domain_d)+DOMAIN(d)->namelen);
187 }
188
189 /** delete domain but also unlink from tree at zone */
190 static void
domain_delete_unlink(udb_base * udb,udb_ptr * z,udb_ptr * d)191 domain_delete_unlink(udb_base* udb, udb_ptr* z, udb_ptr* d)
192 {
193 udb_ptr dtree, n;
194 udb_ptr_new(&dtree, udb, &ZONE(z)->domains);
195 udb_ptr_new(&n, udb, &DOMAIN(d)->node);
196 udb_rptr_zero(&DOMAIN(d)->node, udb);
197 udb_radix_delete(udb, &dtree, &n);
198 udb_ptr_unlink(&dtree, udb);
199 udb_ptr_unlink(&n, udb);
200 domain_delete(udb, d);
201 }
202
203 void
udb_zone_clear(udb_base * udb,udb_ptr * zone)204 udb_zone_clear(udb_base* udb, udb_ptr* zone)
205 {
206 udb_ptr dtree, d;
207 assert(udb_ptr_get_type(zone) == udb_chunk_type_zone);
208 udb_ptr_new(&dtree, udb, &ZONE(zone)->domains);
209 udb_rptr_zero(&ZONE(zone)->nsec3param, udb);
210 udb_zone_set_log_str(udb, zone, NULL);
211 udb_zone_set_file_str(udb, zone, NULL);
212
213 /* walk and delete all domains, rrsets, rrs, but keep tree */
214 for(udb_radix_first(udb, &dtree, &d); d.data; udb_radix_next(udb, &d)){
215 udb_ptr domain;
216 udb_ptr_new(&domain, udb, &RADNODE(&d)->elem);
217 udb_rptr_zero(&RADNODE(&d)->elem, udb);
218 domain_delete(udb, &domain);
219 }
220 udb_ptr_unlink(&d, udb);
221 udb_radix_tree_clear(udb, &dtree);
222 ZONE(zone)->rrset_count = 0;
223 ZONE(zone)->rr_count = 0;
224 ZONE(zone)->expired = 0;
225 ZONE(zone)->mtime = 0;
226 ZONE(zone)->mtime_nsec = 0;
227 udb_ptr_unlink(&dtree, udb);
228 }
229
230 void
udb_zone_delete(udb_base * udb,udb_ptr * zone)231 udb_zone_delete(udb_base* udb, udb_ptr* zone)
232 {
233 udb_ptr ztree, n;
234 udb_ptr_new(&ztree, udb, udb_base_get_userdata(udb));
235 udb_ptr_new(&n, udb, &ZONE(zone)->node);
236 udb_rptr_zero(&ZONE(zone)->node, udb);
237 udb_radix_delete(udb, &ztree, &n);
238 udb_ptr_unlink(&ztree, udb);
239 udb_ptr_unlink(&n, udb);
240 udb_zone_delete_plain(udb, zone);
241 }
242
243 int
udb_zone_search(udb_base * udb,udb_ptr * result,const uint8_t * dname,size_t dname_len)244 udb_zone_search(udb_base* udb, udb_ptr* result, const uint8_t* dname,
245 size_t dname_len)
246 {
247 udb_ptr ztree;
248 udb_ptr_new(&ztree, udb, udb_base_get_userdata(udb));
249 assert(udb_ptr_get_type(&ztree) == udb_chunk_type_radtree);
250 if(udb_radname_search(udb, &ztree, dname, dname_len, result)) {
251 if(result->data)
252 udb_ptr_set_rptr(result, udb, &RADNODE(result)->elem);
253 udb_ptr_unlink(&ztree, udb);
254 return (result->data != 0);
255 }
256 udb_ptr_unlink(&ztree, udb);
257 return 0;
258 }
259
udb_zone_get_mtime(udb_base * udb,const uint8_t * dname,size_t dlen,struct timespec * mtime)260 void udb_zone_get_mtime(udb_base* udb, const uint8_t* dname, size_t dlen,
261 struct timespec* mtime)
262 {
263 udb_ptr z;
264 if(udb_zone_search(udb, &z, dname, dlen)) {
265 mtime->tv_sec = ZONE(&z)->mtime;
266 mtime->tv_nsec = ZONE(&z)->mtime_nsec;
267 udb_ptr_unlink(&z, udb);
268 return;
269 }
270 mtime->tv_sec = 0;
271 mtime->tv_nsec = 0;
272 }
273
udb_zone_set_log_str(udb_base * udb,udb_ptr * zone,const char * str)274 void udb_zone_set_log_str(udb_base* udb, udb_ptr* zone, const char* str)
275 {
276 /* delete original log str (if any) */
277 if(ZONE(zone)->log_str.data) {
278 udb_ptr s;
279 size_t sz;
280 udb_ptr_new(&s, udb, &ZONE(zone)->log_str);
281 udb_rptr_zero(&ZONE(zone)->log_str, udb);
282 sz = strlen((char*)udb_ptr_data(&s))+1;
283 udb_ptr_free_space(&s, udb, sz);
284 }
285
286 /* set new log str */
287 if(str) {
288 udb_ptr s;
289 size_t sz = strlen(str)+1;
290 if(!udb_ptr_alloc_space(&s, udb, udb_chunk_type_data, sz)) {
291 return; /* failed to allocate log string */
292 }
293 memmove(udb_ptr_data(&s), str, sz);
294 udb_rptr_set_ptr(&ZONE(zone)->log_str, udb, &s);
295 udb_ptr_unlink(&s, udb);
296 }
297 }
298
udb_zone_set_file_str(udb_base * udb,udb_ptr * zone,const char * str)299 void udb_zone_set_file_str(udb_base* udb, udb_ptr* zone, const char* str)
300 {
301 /* delete original file str (if any) */
302 if(ZONE(zone)->file_str.data) {
303 udb_ptr s;
304 size_t sz;
305 udb_ptr_new(&s, udb, &ZONE(zone)->file_str);
306 udb_rptr_zero(&ZONE(zone)->file_str, udb);
307 sz = strlen((char*)udb_ptr_data(&s))+1;
308 udb_ptr_free_space(&s, udb, sz);
309 }
310
311 /* set new file str */
312 if(str) {
313 udb_ptr s;
314 size_t sz = strlen(str)+1;
315 if(!udb_ptr_alloc_space(&s, udb, udb_chunk_type_data, sz)) {
316 return; /* failed to allocate file string */
317 }
318 memmove(udb_ptr_data(&s), str, sz);
319 udb_rptr_set_ptr(&ZONE(zone)->file_str, udb, &s);
320 udb_ptr_unlink(&s, udb);
321 }
322 }
323
udb_zone_get_file_str(udb_base * udb,const uint8_t * dname,size_t dlen)324 const char* udb_zone_get_file_str(udb_base* udb, const uint8_t* dname,
325 size_t dlen)
326 {
327 udb_ptr z;
328 if(udb_zone_search(udb, &z, dname, dlen)) {
329 const char* str;
330 if(ZONE(&z)->file_str.data) {
331 udb_ptr s;
332 udb_ptr_new(&s, udb, &ZONE(&z)->file_str);
333 str = (const char*)udb_ptr_data(&s);
334 udb_ptr_unlink(&s, udb);
335 } else str = NULL;
336 udb_ptr_unlink(&z, udb);
337 return str;
338 }
339 return NULL;
340 }
341
342 #ifdef NSEC3
343 /** select the nsec3param for nsec3 usage */
344 static void
select_nsec3_param(udb_base * udb,udb_ptr * zone,udb_ptr * rrset)345 select_nsec3_param(udb_base* udb, udb_ptr* zone, udb_ptr* rrset)
346 {
347 udb_ptr rr;
348 udb_ptr_new(&rr, udb, &RRSET(rrset)->rrs);
349 while(rr.data) {
350 if(RR(&rr)->len >= 5 && RR(&rr)->wire[0] == NSEC3_SHA1_HASH &&
351 RR(&rr)->wire[1] == 0) {
352 udb_rptr_set_ptr(&ZONE(zone)->nsec3param, udb, &rr);
353 udb_ptr_unlink(&rr, udb);
354 return;
355 }
356 udb_ptr_set_rptr(&rr, udb, &RR(&rr)->next);
357 }
358 udb_ptr_unlink(&rr, udb);
359 }
360
361 const char*
udb_nsec3param_string(udb_ptr * rr)362 udb_nsec3param_string(udb_ptr* rr)
363 {
364 /* max saltlenth plus first couple of numbers (3+1+5+1+3+1) */
365 static char params[MAX_RDLENGTH*2+16];
366 char* p;
367 assert(RR(rr)->len >= 5);
368 p = params + snprintf(params, sizeof(params), "%u %u %u ",
369 (unsigned)RR(rr)->wire[0], (unsigned)RR(rr)->wire[1],
370 (unsigned)read_uint16(&RR(rr)->wire[2]));
371 if(RR(rr)->wire[4] == 0) {
372 *p++ = '-';
373 } else {
374 assert(RR(rr)->len >= 5+RR(rr)->wire[4]);
375 p += hex_ntop(&RR(rr)->wire[5], RR(rr)->wire[4], p,
376 sizeof(params)-strlen(params)-1);
377 }
378 *p = 0;
379 return params;
380 }
381
382 /** look in zone for new selected nsec3param record from rrset */
383 static void
zone_hash_nsec3param(udb_base * udb,udb_ptr * zone,udb_ptr * rrset)384 zone_hash_nsec3param(udb_base* udb, udb_ptr* zone, udb_ptr* rrset)
385 {
386 select_nsec3_param(udb, zone, rrset);
387 if(ZONE(zone)->nsec3param.data == 0)
388 return;
389 /* prettyprint the nsec3 parameters we are using */
390 if(2 <= verbosity) {
391 udb_ptr par;
392 udb_ptr_new(&par, udb, &ZONE(zone)->nsec3param);
393 VERBOSITY(1, (LOG_INFO, "rehash of zone %s with parameters %s",
394 wiredname2str(ZONE(zone)->name),
395 udb_nsec3param_string(&par)));
396 udb_ptr_unlink(&par, udb);
397 }
398 }
399 #endif /* NSEC3 */
400
401 /** create a new domain name */
402 static int
domain_create(udb_base * udb,udb_ptr * zone,const uint8_t * nm,size_t nmlen,udb_ptr * result)403 domain_create(udb_base* udb, udb_ptr* zone, const uint8_t* nm, size_t nmlen,
404 udb_ptr* result)
405 {
406 udb_ptr dtree, node;
407 /* create domain chunk */
408 if(!udb_ptr_alloc_space(result, udb, udb_chunk_type_domain,
409 sizeof(struct domain_d)+nmlen))
410 return 0;
411 udb_rel_ptr_init(&DOMAIN(result)->node);
412 udb_rel_ptr_init(&DOMAIN(result)->rrsets);
413 DOMAIN(result)->namelen = nmlen;
414 memmove(DOMAIN(result)->name, nm, nmlen);
415
416 /* insert into domain tree */
417 udb_ptr_new(&dtree, udb, &ZONE(zone)->domains);
418 if(!udb_radname_insert(udb, &dtree, nm, nmlen, result, &node)) {
419 udb_ptr_free_space(result, udb, sizeof(struct domain_d)+nmlen);
420 udb_ptr_unlink(&dtree, udb);
421 return 0;
422 }
423 udb_rptr_set_ptr(&DOMAIN(result)->node, udb, &node);
424 udb_ptr_unlink(&dtree, udb);
425 udb_ptr_unlink(&node, udb);
426 return 1;
427 }
428
429 int
udb_domain_find(udb_base * udb,udb_ptr * zone,const uint8_t * nm,size_t nmlen,udb_ptr * result)430 udb_domain_find(udb_base* udb, udb_ptr* zone, const uint8_t* nm, size_t nmlen,
431 udb_ptr* result)
432 {
433 int r;
434 udb_ptr dtree;
435 assert(udb_ptr_get_type(zone) == udb_chunk_type_zone);
436 udb_ptr_new(&dtree, udb, &ZONE(zone)->domains);
437 r = udb_radname_search(udb, &dtree, nm, nmlen, result);
438 if(result->data)
439 udb_ptr_set_rptr(result, udb, &RADNODE(result)->elem);
440 udb_ptr_unlink(&dtree, udb);
441 return r && result->data;
442 }
443
444 /** find or create a domain name in the zone domain tree */
445 static int
domain_find_or_create(udb_base * udb,udb_ptr * zone,const uint8_t * nm,size_t nmlen,udb_ptr * result)446 domain_find_or_create(udb_base* udb, udb_ptr* zone, const uint8_t* nm,
447 size_t nmlen, udb_ptr* result)
448 {
449 assert(udb_ptr_get_type(zone) == udb_chunk_type_zone);
450 if(udb_domain_find(udb, zone, nm, nmlen, result))
451 return 1;
452 return domain_create(udb, zone, nm, nmlen, result);
453 }
454
455 /** remove rrset from the domain name rrset-list */
456 static void
domain_remove_rrset(udb_base * udb,udb_ptr * domain,uint16_t t)457 domain_remove_rrset(udb_base* udb, udb_ptr* domain, uint16_t t)
458 {
459 udb_ptr p, prev;
460 assert(udb_ptr_get_type(domain) == udb_chunk_type_domain);
461 udb_ptr_new(&p, udb, &DOMAIN(domain)->rrsets);
462 udb_ptr_init(&prev, udb);
463 while(p.data) {
464 if(RRSET(&p)->type == t) {
465 /* remove it */
466 if(prev.data == 0) {
467 /* first rrset */
468 udb_rptr_set_rptr(&DOMAIN(domain)->rrsets,
469 udb, &RRSET(&p)->next);
470 } else {
471 udb_rptr_set_rptr(&RRSET(&prev)->next,
472 udb, &RRSET(&p)->next);
473 }
474 udb_ptr_unlink(&prev, udb);
475 rrset_delete(udb, &p);
476 return;
477 }
478 udb_ptr_set_ptr(&prev, udb, &p);
479 udb_ptr_set_rptr(&p, udb, &RRSET(&p)->next);
480 }
481 /* rrset does not exist */
482 udb_ptr_unlink(&prev, udb);
483 udb_ptr_unlink(&p, udb);
484 }
485
486 /** create rrset in the domain rrset list */
487 static int
rrset_create(udb_base * udb,udb_ptr * domain,uint16_t t,udb_ptr * res)488 rrset_create(udb_base* udb, udb_ptr* domain, uint16_t t, udb_ptr* res)
489 {
490 /* create it */
491 if(!udb_ptr_alloc_space(res, udb, udb_chunk_type_rrset,
492 sizeof(struct rrset_d)))
493 return 0;
494 udb_rel_ptr_init(&RRSET(res)->next);
495 udb_rel_ptr_init(&RRSET(res)->rrs);
496 RRSET(res)->type = t;
497
498 #if 0
499 /* link it in, at the front */
500 udb_rptr_set_rptr(&RRSET(res)->next, udb, &DOMAIN(domain)->rrsets);
501 udb_rptr_set_ptr(&DOMAIN(domain)->rrsets, udb, res);
502 #else
503 /* preserve RRset order, link at end */
504 if(DOMAIN(domain)->rrsets.data == 0) {
505 udb_rptr_set_ptr(&DOMAIN(domain)->rrsets, udb, res);
506 } else {
507 udb_ptr p;
508 udb_ptr_new(&p, udb, &DOMAIN(domain)->rrsets);
509 while(RRSET(&p)->next.data)
510 udb_ptr_set_rptr(&p, udb, &RRSET(&p)->next);
511 udb_rptr_set_ptr(&RRSET(&p)->next, udb, res);
512 udb_ptr_unlink(&p, udb);
513 }
514 #endif
515 return 1;
516 }
517
518 int
udb_rrset_find(udb_base * udb,udb_ptr * domain,uint16_t t,udb_ptr * res)519 udb_rrset_find(udb_base* udb, udb_ptr* domain, uint16_t t, udb_ptr* res)
520 {
521 assert(udb_ptr_get_type(domain) == udb_chunk_type_domain);
522 udb_ptr_init(res, udb);
523 udb_ptr_set_rptr(res, udb, &DOMAIN(domain)->rrsets);
524 while(res->data) {
525 if(RRSET(res)->type == t)
526 return 1;
527 udb_ptr_set_rptr(res, udb, &RRSET(res)->next);
528 }
529 /* rrset does not exist and res->data is conveniently zero */
530 return 0;
531 }
532
533 /** find or create rrset in the domain rrset list */
534 static int
rrset_find_or_create(udb_base * udb,udb_ptr * domain,uint16_t t,udb_ptr * res)535 rrset_find_or_create(udb_base* udb, udb_ptr* domain, uint16_t t, udb_ptr* res)
536 {
537 if(udb_rrset_find(udb, domain, t, res))
538 return 1;
539 return rrset_create(udb, domain, t, res);
540 }
541
542 /** see if RR matches type, class and rdata */
543 static int
rr_match(udb_ptr * rr,uint16_t t,uint16_t k,uint8_t * rdata,size_t rdatalen)544 rr_match(udb_ptr* rr, uint16_t t, uint16_t k, uint8_t* rdata, size_t rdatalen)
545 {
546 return RR(rr)->type == t && RR(rr)->klass == k &&
547 RR(rr)->len == rdatalen &&
548 memcmp(RR(rr)->wire, rdata, rdatalen) == 0;
549 }
550
551 /** see if RR exists in the RR list that matches the rdata, and return it */
552 static int
rr_search(udb_base * udb,udb_ptr * rrset,uint16_t t,uint16_t k,uint8_t * rdata,size_t rdatalen,udb_ptr * result)553 rr_search(udb_base* udb, udb_ptr* rrset, uint16_t t, uint16_t k,
554 uint8_t* rdata, size_t rdatalen, udb_ptr* result)
555 {
556 assert(udb_ptr_get_type(rrset) == udb_chunk_type_rrset);
557 udb_ptr_init(result, udb);
558 udb_ptr_set_rptr(result, udb, &RRSET(rrset)->rrs);
559 while(result->data) {
560 if(rr_match(result, t, k, rdata, rdatalen))
561 return 1; /* found */
562 udb_ptr_set_rptr(result, udb, &RR(result)->next);
563 }
564 /* not found and result->data is conveniently zero */
565 return 0;
566 }
567
568 /** create RR chunk */
569 static int
rr_create(udb_base * udb,uint16_t t,uint16_t k,uint32_t ttl,uint8_t * rdata,size_t rdatalen,udb_ptr * rr)570 rr_create(udb_base* udb, uint16_t t, uint16_t k, uint32_t ttl,
571 uint8_t* rdata, size_t rdatalen, udb_ptr* rr)
572 {
573 if(!udb_ptr_alloc_space(rr, udb, udb_chunk_type_rr,
574 sizeof(struct rr_d)+rdatalen))
575 return 0;
576 udb_rel_ptr_init(&RR(rr)->next);
577 RR(rr)->type = t;
578 RR(rr)->klass = k;
579 RR(rr)->ttl = ttl;
580 RR(rr)->len = rdatalen;
581 memmove(RR(rr)->wire, rdata, rdatalen);
582 return 1;
583 }
584
585 /** add an RR to an RRset. */
586 static int
rrset_add_rr(udb_base * udb,udb_ptr * rrset,uint16_t t,uint16_t k,uint32_t ttl,uint8_t * rdata,size_t rdatalen)587 rrset_add_rr(udb_base* udb, udb_ptr* rrset, uint16_t t, uint16_t k,
588 uint32_t ttl, uint8_t* rdata, size_t rdatalen)
589 {
590 udb_ptr rr;
591 assert(udb_ptr_get_type(rrset) == udb_chunk_type_rrset);
592 /* create it */
593 if(!rr_create(udb, t, k, ttl, rdata, rdatalen, &rr))
594 return 0;
595
596 /* add at end, to preserve order of RRs */
597 if(RRSET(rrset)->rrs.data == 0) {
598 udb_rptr_set_ptr(&RRSET(rrset)->rrs, udb, &rr);
599 } else {
600 udb_ptr lastrr;
601 udb_ptr_new(&lastrr, udb, &RRSET(rrset)->rrs);
602 while(RR(&lastrr)->next.data)
603 udb_ptr_set_rptr(&lastrr, udb, &RR(&lastrr)->next);
604 udb_rptr_set_ptr(&RR(&lastrr)->next, udb, &rr);
605 udb_ptr_unlink(&lastrr, udb);
606 }
607 udb_ptr_unlink(&rr, udb);
608 return 1;
609 }
610
611 /** remove an RR from an RRset. return 0 if RR did not exist. */
612 static int
rrset_del_rr(udb_base * udb,udb_ptr * rrset,uint16_t t,uint16_t k,uint8_t * rdata,size_t rdatalen)613 rrset_del_rr(udb_base* udb, udb_ptr* rrset, uint16_t t, uint16_t k,
614 uint8_t* rdata, size_t rdatalen)
615 {
616 udb_ptr p, prev;
617 assert(udb_ptr_get_type(rrset) == udb_chunk_type_rrset);
618 udb_ptr_new(&p, udb, &RRSET(rrset)->rrs);
619 udb_ptr_init(&prev, udb);
620 while(p.data) {
621 if(rr_match(&p, t, k, rdata, rdatalen)) {
622 /* remove it */
623 if(prev.data == 0) {
624 /* first in list */
625 udb_rptr_set_rptr(&RRSET(rrset)->rrs, udb,
626 &RR(&p)->next);
627 } else {
628 udb_rptr_set_rptr(&RR(&prev)->next, udb,
629 &RR(&p)->next);
630 }
631 udb_ptr_unlink(&prev, udb);
632 rr_delete(udb, &p);
633 return 1;
634 }
635 udb_ptr_set_ptr(&prev, udb, &p);
636 udb_ptr_set_rptr(&p, udb, &RR(&p)->next);
637 }
638 /* not found */
639 udb_ptr_unlink(&prev, udb);
640 udb_ptr_unlink(&p, udb);
641 return 0;
642 }
643
644 int
udb_zone_add_rr(udb_base * udb,udb_ptr * zone,const uint8_t * nm,size_t nmlen,uint16_t t,uint16_t k,uint32_t ttl,uint8_t * rdata,size_t rdatalen)645 udb_zone_add_rr(udb_base* udb, udb_ptr* zone, const uint8_t* nm, size_t nmlen,
646 uint16_t t, uint16_t k, uint32_t ttl, uint8_t* rdata, size_t rdatalen)
647 {
648 udb_ptr domain, rrset, rr;
649 int created_rrset = 0;
650 assert(udb_ptr_get_type(zone) == udb_chunk_type_zone);
651
652 /* find or create domain */
653 if(!domain_find_or_create(udb, zone, nm, nmlen, &domain)) {
654 return 0;
655 }
656 /* find or create rrset(type) */
657 if(!rrset_find_or_create(udb, &domain, t, &rrset)) {
658 goto exit_clean_domain;
659 }
660 if(RRSET(&rrset)->rrs.data == 0)
661 created_rrset = 1;
662 /* test for duplicate RRs */
663 if(rr_search(udb, &rrset, t, k, rdata, rdatalen, &rr)) {
664 udb_ptr_unlink(&rr, udb);
665 goto exit_clean_domain_rrset;
666 }
667 /* add RR to rrset */
668 if(!rrset_add_rr(udb, &rrset, t, k, ttl, rdata, rdatalen)) {
669 exit_clean_domain_rrset:
670 /* if rrset was created, remove it */
671 if(RRSET(&rrset)->rrs.data == 0) {
672 udb_ptr_zero(&rrset, udb);
673 domain_remove_rrset(udb, &domain, t);
674 }
675 udb_ptr_unlink(&rrset, udb);
676 exit_clean_domain:
677 /* if domain created, delete it */
678 if(DOMAIN(&domain)->rrsets.data == 0)
679 domain_delete_unlink(udb, zone, &domain);
680 udb_ptr_unlink(&domain, udb);
681 return 0;
682 }
683 /* success, account changes */
684 if(created_rrset)
685 ZONE(zone)->rrset_count ++;
686 ZONE(zone)->rr_count ++;
687 #ifdef NSEC3
688 if(t == TYPE_NSEC3PARAM && ZONE(zone)->nsec3param.data == 0)
689 zone_hash_nsec3param(udb, zone, &rrset);
690 #endif /* NSEC3 */
691 udb_ptr_unlink(&domain, udb);
692 udb_ptr_unlink(&rrset, udb);
693 return 1;
694 }
695
696 void
udb_zone_del_rr(udb_base * udb,udb_ptr * zone,const uint8_t * nm,size_t nmlen,uint16_t t,uint16_t k,uint8_t * rdata,size_t rdatalen)697 udb_zone_del_rr(udb_base* udb, udb_ptr* zone, const uint8_t* nm, size_t nmlen,
698 uint16_t t, uint16_t k, uint8_t* rdata, size_t rdatalen)
699 {
700 udb_ptr domain, rrset;
701 assert(udb_ptr_get_type(zone) == udb_chunk_type_zone);
702 /* find the domain */
703 if(!udb_domain_find(udb, zone, nm, nmlen, &domain))
704 return;
705 /* find the rrset */
706 if(!udb_rrset_find(udb, &domain, t, &rrset)) {
707 udb_ptr_unlink(&domain, udb);
708 return;
709 }
710 /* remove the RR */
711 #ifdef NSEC3
712 if(t == TYPE_NSEC3PARAM) {
713 udb_ptr rr;
714 if(rr_search(udb, &rrset, t, k, rdata, rdatalen, &rr)) {
715 if(rr.data == ZONE(zone)->nsec3param.data) {
716 udb_rptr_zero(&ZONE(zone)->nsec3param, udb);
717 }
718 udb_ptr_unlink(&rr, udb);
719 }
720 }
721 #endif /* NSEC3 */
722 if(!rrset_del_rr(udb, &rrset, t, k, rdata, rdatalen)) {
723 /* rr did not exist */
724 udb_ptr_unlink(&domain, udb);
725 udb_ptr_unlink(&rrset, udb);
726 return;
727 }
728 ZONE(zone)->rr_count --;
729 #ifdef NSEC3
730 if(t == TYPE_NSEC3PARAM && ZONE(zone)->nsec3param.data == 0 &&
731 RRSET(&rrset)->rrs.data != 0) {
732 zone_hash_nsec3param(udb, zone, &rrset);
733 }
734 #endif /* NSEC3 */
735 /* see we we can remove the rrset too */
736 if(RRSET(&rrset)->rrs.data == 0) {
737 udb_ptr_zero(&rrset, udb);
738 domain_remove_rrset(udb, &domain, t);
739 ZONE(zone)->rrset_count --;
740 }
741 /* see if we can remove the domain name too */
742 if(DOMAIN(&domain)->rrsets.data == 0) {
743 domain_delete_unlink(udb, zone, &domain);
744 }
745 udb_ptr_unlink(&rrset, udb);
746 udb_ptr_unlink(&domain, udb);
747 }
748
749 void
udb_zone_walk_chunk(void * base,void * d,uint64_t s,udb_walk_relptr_cb * cb,void * arg)750 udb_zone_walk_chunk(void* base, void* d, uint64_t s, udb_walk_relptr_cb* cb,
751 void* arg)
752 {
753 struct zone_d* p = (struct zone_d*)d;
754 assert(s >= sizeof(struct zone_d)+p->namelen);
755 (void)s;
756 (*cb)(base, &p->node, arg);
757 (*cb)(base, &p->domains, arg);
758 (*cb)(base, &p->nsec3param, arg);
759 (*cb)(base, &p->log_str, arg);
760 (*cb)(base, &p->file_str, arg);
761 }
762
763 void
udb_domain_walk_chunk(void * base,void * d,uint64_t s,udb_walk_relptr_cb * cb,void * arg)764 udb_domain_walk_chunk(void* base, void* d, uint64_t s, udb_walk_relptr_cb* cb,
765 void* arg)
766 {
767 struct domain_d* p = (struct domain_d*)d;
768 assert(s >= sizeof(struct domain_d)+p->namelen);
769 (void)s;
770 (*cb)(base, &p->node, arg);
771 (*cb)(base, &p->rrsets, arg);
772 }
773
774 void
udb_rrset_walk_chunk(void * base,void * d,uint64_t s,udb_walk_relptr_cb * cb,void * arg)775 udb_rrset_walk_chunk(void* base, void* d, uint64_t s, udb_walk_relptr_cb* cb,
776 void* arg)
777 {
778 struct rrset_d* p = (struct rrset_d*)d;
779 assert(s >= sizeof(struct rrset_d));
780 (void)s;
781 (*cb)(base, &p->next, arg);
782 (*cb)(base, &p->rrs, arg);
783 }
784
785 void
udb_rr_walk_chunk(void * base,void * d,uint64_t s,udb_walk_relptr_cb * cb,void * arg)786 udb_rr_walk_chunk(void* base, void* d, uint64_t s, udb_walk_relptr_cb* cb,
787 void* arg)
788 {
789 struct rr_d* p = (struct rr_d*)d;
790 assert(s >= sizeof(struct rr_d)+p->len);
791 (void)s;
792 (*cb)(base, &p->next, arg);
793 }
794
795 void
udb_task_walk_chunk(void * base,void * d,uint64_t s,udb_walk_relptr_cb * cb,void * arg)796 udb_task_walk_chunk(void* base, void* d, uint64_t s, udb_walk_relptr_cb* cb,
797 void* arg)
798 {
799 struct task_list_d* p = (struct task_list_d*)d;
800 assert(s >= p->size);
801 (void)s;
802 (*cb)(base, &p->next, arg);
803 }
804
namedb_walkfunc(void * base,void * warg,uint8_t t,void * d,uint64_t s,udb_walk_relptr_cb * cb,void * arg)805 void namedb_walkfunc(void* base, void* warg, uint8_t t, void* d, uint64_t s,
806 udb_walk_relptr_cb* cb, void* arg)
807 {
808 (void)warg;
809 switch(t) {
810 case udb_chunk_type_radtree:
811 udb_radix_tree_walk_chunk(base, d, s, cb, arg);
812 break;
813 case udb_chunk_type_radnode:
814 udb_radix_node_walk_chunk(base, d, s, cb, arg);
815 break;
816 case udb_chunk_type_radarray:
817 udb_radix_array_walk_chunk(base, d, s, cb, arg);
818 break;
819 case udb_chunk_type_zone:
820 udb_zone_walk_chunk(base, d, s, cb, arg);
821 break;
822 case udb_chunk_type_domain:
823 udb_domain_walk_chunk(base, d, s, cb, arg);
824 break;
825 case udb_chunk_type_rrset:
826 udb_rrset_walk_chunk(base, d, s, cb, arg);
827 break;
828 case udb_chunk_type_rr:
829 udb_rr_walk_chunk(base, d, s, cb, arg);
830 break;
831 case udb_chunk_type_task:
832 udb_task_walk_chunk(base, d, s, cb, arg);
833 break;
834 default:
835 /* no rel ptrs */
836 break;
837 }
838 }
839