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