xref: /netbsd/external/bsd/nsd/dist/dbaccess.c (revision 66a1527d)
1 /*
2  * dbaccess.c -- access methods for nsd(8) database
3  *
4  * Copyright (c) 2001-2006, NLnet Labs. All rights reserved.
5  *
6  * See LICENSE for the license.
7  *
8  */
9 
10 #include "config.h"
11 
12 #include <sys/types.h>
13 #include <sys/stat.h>
14 
15 #include <errno.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <unistd.h>
19 #include <fcntl.h>
20 
21 #include "dns.h"
22 #include "namedb.h"
23 #include "util.h"
24 #include "options.h"
25 #include "rdata.h"
26 #include "udb.h"
27 #include "udbradtree.h"
28 #include "udbzone.h"
29 #include "zonec.h"
30 #include "nsec3.h"
31 #include "difffile.h"
32 #include "nsd.h"
33 #include "ixfr.h"
34 #include "ixfrcreate.h"
35 
36 static time_t udb_time = 0;
37 static unsigned long udb_rrsets = 0;
38 static unsigned long udb_rrset_count = 0;
39 
40 void
namedb_close(struct namedb * db)41 namedb_close(struct namedb* db)
42 {
43 	if(db) {
44 		if(db->udb) {
45 			udb_base_close(db->udb);
46 			udb_base_free(db->udb);
47 			db->udb = NULL;
48 		}
49 		zonec_desetup_parser();
50 		region_destroy(db->region);
51 	}
52 }
53 
54 void
namedb_close_udb(struct namedb * db)55 namedb_close_udb(struct namedb* db)
56 {
57 	if(db) {
58 		/* we cannot actually munmap the data, because other
59 		 * processes still need to access the udb, so cleanup the
60 		 * udb */
61 		udb_base_free_keep_mmap(db->udb);
62 		db->udb = NULL;
63 	}
64 }
65 
66 void
namedb_free_ixfr(struct namedb * db)67 namedb_free_ixfr(struct namedb* db)
68 {
69 	struct radnode* n;
70 	for(n=radix_first(db->zonetree); n; n=radix_next(n)) {
71 		zone_ixfr_free(((zone_type*)n->elem)->ixfr);
72 	}
73 }
74 
75 /** read rr */
76 static void
read_rr(namedb_type * db,rr_type * rr,udb_ptr * urr,domain_type * domain)77 read_rr(namedb_type* db, rr_type* rr, udb_ptr* urr, domain_type* domain)
78 {
79 	buffer_type buffer;
80 	ssize_t c;
81 	assert(udb_ptr_get_type(urr) == udb_chunk_type_rr);
82 	rr->owner = domain;
83 	rr->type = RR(urr)->type;
84 	rr->klass = RR(urr)->klass;
85 	rr->ttl = RR(urr)->ttl;
86 
87 	buffer_create_from(&buffer, RR(urr)->wire, RR(urr)->len);
88 	c = rdata_wireformat_to_rdata_atoms(db->region, db->domains,
89 		rr->type, RR(urr)->len, &buffer, &rr->rdatas);
90 	if(c == -1) {
91 		/* safe on error */
92 		rr->rdata_count = 0;
93 		rr->rdatas = NULL;
94 		return;
95 	}
96 	rr->rdata_count = c;
97 }
98 
99 /** calculate rr count */
100 static uint16_t
calculate_rr_count(udb_base * udb,udb_ptr * rrset)101 calculate_rr_count(udb_base* udb, udb_ptr* rrset)
102 {
103 	udb_ptr rr;
104 	uint16_t num = 0;
105 	udb_ptr_new(&rr, udb, &RRSET(rrset)->rrs);
106 	while(rr.data) {
107 		num++;
108 		udb_ptr_set_rptr(&rr, udb, &RR(&rr)->next);
109 	}
110 	udb_ptr_unlink(&rr, udb);
111 	return num;
112 }
113 
114 /** read rrset */
115 static void
read_rrset(udb_base * udb,namedb_type * db,zone_type * zone,domain_type * domain,udb_ptr * urrset)116 read_rrset(udb_base* udb, namedb_type* db, zone_type* zone,
117 	domain_type* domain, udb_ptr* urrset)
118 {
119 	rrset_type* rrset;
120 	udb_ptr urr;
121 	unsigned i;
122 	assert(udb_ptr_get_type(urrset) == udb_chunk_type_rrset);
123 	/* if no RRs, do not create anything (robust) */
124 	if(RRSET(urrset)->rrs.data == 0)
125 		return;
126 	rrset = (rrset_type *) region_alloc(db->region, sizeof(rrset_type));
127 	rrset->zone = zone;
128 	rrset->rr_count = calculate_rr_count(udb, urrset);
129 	rrset->rrs = (rr_type *) region_alloc_array(
130 		db->region, rrset->rr_count, sizeof(rr_type));
131 	/* add the RRs */
132 	udb_ptr_new(&urr, udb, &RRSET(urrset)->rrs);
133 	for(i=0; i<rrset->rr_count; i++) {
134 		read_rr(db, &rrset->rrs[i], &urr, domain);
135 		udb_ptr_set_rptr(&urr, udb, &RR(&urr)->next);
136 	}
137 	udb_ptr_unlink(&urr, udb);
138 	domain_add_rrset(domain, rrset);
139 	if(domain == zone->apex)
140 		apex_rrset_checks(db, rrset, domain);
141 }
142 
143 /** read one elem from db, of type domain_d */
read_node_elem(udb_base * udb,namedb_type * db,region_type * dname_region,zone_type * zone,struct domain_d * d)144 static void read_node_elem(udb_base* udb, namedb_type* db,
145 	region_type* dname_region, zone_type* zone, struct domain_d* d)
146 {
147 	const dname_type* dname;
148 	domain_type* domain;
149 	udb_ptr urrset;
150 
151 	dname = dname_make(dname_region, d->name, 0);
152 	if(!dname) return;
153 	domain = domain_table_insert(db->domains, dname);
154 	assert(domain); /* domain_table_insert should always return non-NULL */
155 
156 	/* add rrsets */
157 	udb_ptr_init(&urrset, udb);
158 	udb_ptr_set_rptr(&urrset, udb, &d->rrsets);
159 	while(urrset.data) {
160 		read_rrset(udb, db, zone, domain, &urrset);
161 		udb_ptr_set_rptr(&urrset, udb, &RRSET(&urrset)->next);
162 
163 		if(++udb_rrsets % ZONEC_PCT_COUNT == 0 && time(NULL) > udb_time + ZONEC_PCT_TIME) {
164 			udb_time = time(NULL);
165 			VERBOSITY(1, (LOG_INFO, "read %s %d %%",
166 				zone->opts->name,
167 				(int)(udb_rrsets*((unsigned long)100)/udb_rrset_count)));
168 		}
169 	}
170 	region_free_all(dname_region);
171 	udb_ptr_unlink(&urrset, udb);
172 }
173 
174 /** recurse read radix from disk. This radix tree is by domain name, so max of
175  * 256 depth, and thus the stack usage is small. */
read_zone_recurse(udb_base * udb,namedb_type * db,region_type * dname_region,zone_type * zone,struct udb_radnode_d * node)176 static void read_zone_recurse(udb_base* udb, namedb_type* db,
177 	region_type* dname_region, zone_type* zone, struct udb_radnode_d* node)
178 {
179 	if(node->elem.data) {
180 		/* pre-order process of node->elem, for radix tree this is
181 		 * also in-order processing (identical to order tree_next()) */
182 		read_node_elem(udb, db, dname_region, zone, (struct domain_d*)
183 			((char*)udb->base + node->elem.data));
184 	}
185 	if(node->lookup.data) {
186 		uint16_t i;
187 		struct udb_radarray_d* a = (struct udb_radarray_d*)
188 			((char*)udb->base + node->lookup.data);
189 		/* we do not care for what the exact radix key is, we want
190 		 * to add all of them and the read routine does not need
191 		 * the radix-key, it has it stored */
192 		for(i=0; i<a->len; i++) {
193 			if(a->array[i].node.data) {
194 				read_zone_recurse(udb, db, dname_region, zone,
195 					(struct udb_radnode_d*)((char*)udb->base +
196 						a->array[i].node.data));
197 			}
198 		}
199 	}
200 }
201 
202 /** read zone data */
203 static void
read_zone_data(udb_base * udb,namedb_type * db,region_type * dname_region,udb_ptr * z,zone_type * zone)204 read_zone_data(udb_base* udb, namedb_type* db, region_type* dname_region,
205 	udb_ptr* z, zone_type* zone)
206 {
207 	udb_ptr dtree;
208 	/* recursively read domains, we only read so ptrs stay valid */
209 	udb_ptr_new(&dtree, udb, &ZONE(z)->domains);
210 	if(RADTREE(&dtree)->root.data)
211 		read_zone_recurse(udb, db, dname_region, zone,
212 			(struct udb_radnode_d*)
213 			((char*)udb->base + RADTREE(&dtree)->root.data));
214 	udb_ptr_unlink(&dtree, udb);
215 }
216 
217 /** create a zone */
218 zone_type*
namedb_zone_create(namedb_type * db,const dname_type * dname,struct zone_options * zo)219 namedb_zone_create(namedb_type* db, const dname_type* dname,
220 	struct zone_options* zo)
221 {
222 	zone_type* zone = (zone_type *) region_alloc(db->region,
223 		sizeof(zone_type));
224 	zone->node = radname_insert(db->zonetree, dname_name(dname),
225 		dname->name_size, zone);
226 	assert(zone->node);
227 	zone->apex = domain_table_insert(db->domains, dname);
228 	zone->apex->usage++; /* the zone.apex reference */
229 	zone->apex->is_apex = 1;
230 	zone->soa_rrset = NULL;
231 	zone->soa_nx_rrset = NULL;
232 	zone->ns_rrset = NULL;
233 #ifdef NSEC3
234 	zone->nsec3_param = NULL;
235 	zone->nsec3_last = NULL;
236 	zone->nsec3tree = NULL;
237 	zone->hashtree = NULL;
238 	zone->wchashtree = NULL;
239 	zone->dshashtree = NULL;
240 #endif
241 	zone->opts = zo;
242 	zone->ixfr = NULL;
243 	zone->filename = NULL;
244 	zone->logstr = NULL;
245 	zone->mtime.tv_sec = 0;
246 	zone->mtime.tv_nsec = 0;
247 	zone->zonestatid = 0;
248 	zone->is_secure = 0;
249 	zone->is_changed = 0;
250 	zone->is_updated = 0;
251 	zone->is_skipped = 0;
252 	zone->is_checked = 0;
253 	zone->is_bad = 0;
254 	zone->is_ok = 1;
255 	return zone;
256 }
257 
258 void
namedb_zone_delete(namedb_type * db,zone_type * zone)259 namedb_zone_delete(namedb_type* db, zone_type* zone)
260 {
261 	/* RRs and UDB and NSEC3 and so on must be already deleted */
262 	radix_delete(db->zonetree, zone->node);
263 
264 	/* see if apex can be deleted */
265 	if(zone->apex) {
266 		zone->apex->usage --;
267 		zone->apex->is_apex = 0;
268 		if(zone->apex->usage == 0) {
269 			/* delete the apex, possibly */
270 			domain_table_deldomain(db, zone->apex);
271 		}
272 	}
273 
274 	/* soa_rrset is freed when the SOA was deleted */
275 	if(zone->soa_nx_rrset) {
276 		region_recycle(db->region, zone->soa_nx_rrset->rrs,
277 			sizeof(rr_type));
278 		region_recycle(db->region, zone->soa_nx_rrset,
279 			sizeof(rrset_type));
280 	}
281 #ifdef NSEC3
282 	hash_tree_delete(db->region, zone->nsec3tree);
283 	hash_tree_delete(db->region, zone->hashtree);
284 	hash_tree_delete(db->region, zone->wchashtree);
285 	hash_tree_delete(db->region, zone->dshashtree);
286 #endif
287 	zone_ixfr_free(zone->ixfr);
288 	if(zone->filename)
289 		region_recycle(db->region, zone->filename,
290 			strlen(zone->filename)+1);
291 	if(zone->logstr)
292 		region_recycle(db->region, zone->logstr,
293 			strlen(zone->logstr)+1);
294 	region_recycle(db->region, zone, sizeof(zone_type));
295 }
296 
297 #ifdef HAVE_MMAP
298 /** read a zone */
299 static void
read_zone(udb_base * udb,namedb_type * db,struct nsd_options * opt,region_type * dname_region,udb_ptr * z)300 read_zone(udb_base* udb, namedb_type* db, struct nsd_options* opt,
301 	region_type* dname_region, udb_ptr* z)
302 {
303 	/* construct dname */
304 	const dname_type* dname = dname_make(dname_region, ZONE(z)->name, 0);
305 	struct zone_options* zo = dname?zone_options_find(opt, dname):NULL;
306 	zone_type* zone;
307 	if(!dname) return;
308 	if(!zo) {
309 		/* deleted from the options, remove it from the nsd.db too */
310 		VERBOSITY(2, (LOG_WARNING, "zone %s is deleted",
311 			dname_to_string(dname, NULL)));
312 		udb_zone_delete(udb, z);
313 		region_free_all(dname_region);
314 		return;
315 	}
316 	assert(udb_ptr_get_type(z) == udb_chunk_type_zone);
317 	udb_rrsets = 0;
318 	udb_rrset_count = ZONE(z)->rrset_count;
319 	zone = namedb_zone_create(db, dname, zo);
320 	region_free_all(dname_region);
321 	read_zone_data(udb, db, dname_region, z, zone);
322 	zone->is_changed = (ZONE(z)->is_changed != 0);
323 #ifdef NSEC3
324 	prehash_zone_complete(db, zone);
325 #endif
326 }
327 #endif /* HAVE_MMAP */
328 
329 #ifdef HAVE_MMAP
330 /** read zones from nsd.db */
331 static void
read_zones(udb_base * udb,namedb_type * db,struct nsd_options * opt,region_type * dname_region)332 read_zones(udb_base* udb, namedb_type* db, struct nsd_options* opt,
333 	region_type* dname_region)
334 {
335 	udb_ptr ztree, n, z;
336 	udb_ptr_init(&z, udb);
337 	udb_ptr_new(&ztree, udb, udb_base_get_userdata(udb));
338 	udb_radix_first(udb,&ztree,&n);
339 	udb_time = time(NULL);
340 	while(n.data) {
341 		udb_ptr_set_rptr(&z, udb, &RADNODE(&n)->elem);
342 		udb_radix_next(udb, &n); /* store in case n is deleted */
343 		read_zone(udb, db, opt, dname_region, &z);
344 		udb_ptr_zero(&z, udb);
345 		if(nsd.signal_hint_shutdown) break;
346 	}
347 	udb_ptr_unlink(&ztree, udb);
348 	udb_ptr_unlink(&n, udb);
349 	udb_ptr_unlink(&z, udb);
350 }
351 #endif /* HAVE_MMAP */
352 
353 #ifdef HAVE_MMAP
354 /** try to read the udb file or fail */
355 static int
try_read_udb(namedb_type * db,int fd,const char * filename,struct nsd_options * opt)356 try_read_udb(namedb_type* db, int fd, const char* filename,
357 	struct nsd_options* opt)
358 {
359 	/*
360 	 * Temporary region used while loading domain names from the
361 	 * database.  The region is freed after each time a dname is
362 	 * read from the database.
363 	 */
364 	region_type* dname_region;
365 
366 	assert(fd != -1);
367 	if(!(db->udb=udb_base_create_fd(filename, fd, &namedb_walkfunc,
368 		NULL))) {
369 		/* fd is closed by failed udb create call */
370 		VERBOSITY(1, (LOG_ERR, "can not use %s, "
371 			"will create anew", filename));
372 		return 0;
373 	}
374 	/* sanity check if can be opened */
375 	if(udb_base_get_userflags(db->udb) != 0) {
376 		log_msg(LOG_ERR, "%s was not closed properly, it might "
377 			"be corrupted, will create anew", filename);
378 		udb_base_free(db->udb);
379 		db->udb = NULL;
380 		return 0;
381 	}
382 	/* read if it can be opened */
383 	dname_region = region_create(xalloc, free);
384 	/* this operation does not fail, we end up with
385 	 * something, even if that is an empty namedb */
386 	read_zones(db->udb, db, opt, dname_region);
387 	region_destroy(dname_region);
388 	return 1;
389 }
390 #endif /* HAVE_MMAP */
391 
392 struct namedb *
namedb_open(const char * filename,struct nsd_options * opt)393 namedb_open (const char* filename, struct nsd_options* opt)
394 {
395 	namedb_type* db;
396 
397 	/*
398 	 * Region used to store the loaded database.  The region is
399 	 * freed in namedb_close.
400 	 */
401 	region_type* db_region;
402 	int fd;
403 
404 #ifdef USE_MMAP_ALLOC
405 	db_region = region_create_custom(mmap_alloc, mmap_free, MMAP_ALLOC_CHUNK_SIZE,
406 		MMAP_ALLOC_LARGE_OBJECT_SIZE, MMAP_ALLOC_INITIAL_CLEANUP_SIZE, 1);
407 #else /* !USE_MMAP_ALLOC */
408 	db_region = region_create_custom(xalloc, free, DEFAULT_CHUNK_SIZE,
409 		DEFAULT_LARGE_OBJECT_SIZE, DEFAULT_INITIAL_CLEANUP_SIZE, 1);
410 #endif /* !USE_MMAP_ALLOC */
411 	db = (namedb_type *) region_alloc(db_region, sizeof(struct namedb));
412 	db->region = db_region;
413 	db->domains = domain_table_create(db->region);
414 	db->zonetree = radix_tree_create(db->region);
415 	db->diff_skip = 0;
416 	db->diff_pos = 0;
417 	zonec_setup_parser(db);
418 
419 	if (gettimeofday(&(db->diff_timestamp), NULL) != 0) {
420 		log_msg(LOG_ERR, "unable to load %s: cannot initialize"
421 				 "timestamp", filename);
422 		region_destroy(db_region);
423 		return NULL;
424         }
425 
426 	/* in dbless mode there is no file to read or mmap */
427 	if(filename == NULL || filename[0] == 0) {
428 		db->udb = NULL;
429 		return db;
430 	}
431 
432 #ifndef HAVE_MMAP
433 	/* no mmap() system call, use dbless mode */
434 	VERBOSITY(1, (LOG_INFO, "no mmap(), ignoring database %s", filename));
435 	db->udb = NULL;
436 	(void)fd; (void)opt;
437 	return db;
438 #else /* HAVE_MMAP */
439 
440 	/* attempt to open, if does not exist, create a new one */
441 	fd = open(filename, O_RDWR);
442 	if(fd == -1) {
443 		if(errno != ENOENT) {
444 			log_msg(LOG_ERR, "%s: %s", filename, strerror(errno));
445 			region_destroy(db_region);
446 			return NULL;
447 		}
448 	}
449 	/* attempt to read the file (if it exists) */
450 	if(fd != -1) {
451 		if(!try_read_udb(db, fd, filename, opt))
452 			fd = -1;
453 	}
454 	/* attempt to create the file (if necessary or failed read) */
455 	if(fd == -1) {
456 		if(!(db->udb=udb_base_create_new(filename, &namedb_walkfunc,
457 			NULL))) {
458 			region_destroy(db_region);
459 			return NULL;
460 		}
461 		if(!udb_dns_init_file(db->udb)) {
462 			region_destroy(db->region);
463 			return NULL;
464 		}
465 	}
466 	return db;
467 #endif /* HAVE_MMAP */
468 }
469 
470 /** get the file mtime stat (or nonexist or error) */
471 int
file_get_mtime(const char * file,struct timespec * mtime,int * nonexist)472 file_get_mtime(const char* file, struct timespec* mtime, int* nonexist)
473 {
474 	struct stat s;
475 	if(stat(file, &s) != 0) {
476 		mtime->tv_sec = 0;
477 		mtime->tv_nsec = 0;
478 		*nonexist = (errno == ENOENT);
479 		return 0;
480 	}
481 	*nonexist = 0;
482 	mtime->tv_sec = s.st_mtime;
483 #ifdef HAVE_STRUCT_STAT_ST_MTIMENSEC
484 	mtime->tv_nsec = s.st_mtimensec;
485 #elif defined(HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC)
486 	mtime->tv_nsec = s.st_mtim.tv_nsec;
487 #else
488 	mtime->tv_nsec = 0;
489 #endif
490 	return 1;
491 }
492 
493 void
namedb_read_zonefile(struct nsd * nsd,struct zone * zone,udb_base * taskudb,udb_ptr * last_task)494 namedb_read_zonefile(struct nsd* nsd, struct zone* zone, udb_base* taskudb,
495 	udb_ptr* last_task)
496 {
497 	struct timespec mtime;
498 	int nonexist = 0;
499 	unsigned int errors;
500 	const char* fname;
501 	struct ixfr_create* ixfrcr = NULL;
502 	int ixfr_create_already_done = 0;
503 	if(!nsd->db || !zone || !zone->opts || !zone->opts->pattern->zonefile)
504 		return;
505 	mtime.tv_sec = 0;
506 	mtime.tv_nsec = 0;
507 	fname = config_make_zonefile(zone->opts, nsd);
508 	assert(fname);
509 	if(!file_get_mtime(fname, &mtime, &nonexist)) {
510 		if(nonexist) {
511 			if(zone_is_slave(zone->opts)) {
512 				/* for slave zones not as bad, no zonefile
513 				 * may just mean we have to transfer it */
514 				VERBOSITY(2, (LOG_INFO, "zonefile %s does not exist",
515 					fname));
516 			} else {
517 				/* without a download option, we can never
518 				 * serve data, more severe error printout */
519 				log_msg(LOG_ERR, "zonefile %s does not exist", fname);
520 			}
521 
522 		} else
523 			log_msg(LOG_ERR, "zonefile %s: %s",
524 				fname, strerror(errno));
525 		if(taskudb) task_new_soainfo(taskudb, last_task, zone, 0);
526 		return;
527 	} else {
528 		const char* zone_fname = zone->filename;
529 		struct timespec zone_mtime = zone->mtime;
530 		if(nsd->db->udb) {
531 			zone_fname = udb_zone_get_file_str(nsd->db->udb,
532 				dname_name(domain_dname(zone->apex)),
533 				domain_dname(zone->apex)->name_size);
534 			udb_zone_get_mtime(nsd->db->udb,
535 				dname_name(domain_dname(zone->apex)),
536 				domain_dname(zone->apex)->name_size,
537 				&zone_mtime);
538 		}
539 		/* if no zone_fname, then it was acquired in zone transfer,
540 		 * see if the file is newer than the zone transfer
541 		 * (regardless if this is a different file), because the
542 		 * zone transfer is a different content source too */
543 		if(!zone_fname && timespec_compare(&zone_mtime, &mtime) >= 0) {
544 			VERBOSITY(3, (LOG_INFO, "zonefile %s is older than "
545 				"zone transfer in memory", fname));
546 			return;
547 
548 		/* if zone_fname, then the file was acquired from reading it,
549 		 * and see if filename changed or mtime newer to read it */
550 		} else if(zone_fname && strcmp(zone_fname, fname) == 0 &&
551 		   timespec_compare(&zone_mtime, &mtime) == 0) {
552 			VERBOSITY(3, (LOG_INFO, "zonefile %s is not modified",
553 				fname));
554 			return;
555 		}
556 	}
557 	if(ixfr_create_from_difference(zone, fname,
558 		&ixfr_create_already_done)) {
559 		ixfrcr = ixfr_create_start(zone, fname,
560 			zone->opts->pattern->ixfr_size, 0);
561 		if(!ixfrcr) {
562 			/* leaves the ixfrcr at NULL, so it is not created */
563 			log_msg(LOG_ERR, "out of memory starting ixfr create");
564 		}
565 	}
566 
567 	assert(parser);
568 	/* wipe zone from memory */
569 #ifdef NSEC3
570 	nsec3_clear_precompile(nsd->db, zone);
571 	zone->nsec3_param = NULL;
572 #endif
573 	delete_zone_rrs(nsd->db, zone);
574 	errors = zonec_read(zone->opts->name, fname, zone);
575 	if(errors > 0) {
576 		log_msg(LOG_ERR, "zone %s file %s read with %u errors",
577 			zone->opts->name, fname, errors);
578 		/* wipe (partial) zone from memory */
579 		zone->is_ok = 1;
580 #ifdef NSEC3
581 		nsec3_clear_precompile(nsd->db, zone);
582 		zone->nsec3_param = NULL;
583 #endif
584 		delete_zone_rrs(nsd->db, zone);
585 		if(nsd->db->udb) {
586 			region_type* dname_region;
587 			udb_ptr z;
588 			/* see if we can revert to the udb stored version */
589 			if(!udb_zone_search(nsd->db->udb, &z, dname_name(domain_dname(
590 				zone->apex)), domain_dname(zone->apex)->name_size)) {
591 				/* tell that zone contents has been lost */
592 				if(taskudb) task_new_soainfo(taskudb, last_task, zone, 0);
593 				ixfr_create_cancel(ixfrcr);
594 				return;
595 			}
596 			/* read from udb */
597 			dname_region = region_create(xalloc, free);
598 			udb_rrsets = 0;
599 			udb_rrset_count = ZONE(&z)->rrset_count;
600 			udb_time = time(NULL);
601 			read_zone_data(nsd->db->udb, nsd->db, dname_region, &z, zone);
602 			region_destroy(dname_region);
603 			udb_ptr_unlink(&z, nsd->db->udb);
604 		} else {
605 			if(zone->filename)
606 				region_recycle(nsd->db->region, zone->filename,
607 					strlen(zone->filename)+1);
608 			zone->filename = NULL;
609 			if(zone->logstr)
610 				region_recycle(nsd->db->region, zone->logstr,
611 					strlen(zone->logstr)+1);
612 			zone->logstr = NULL;
613 		}
614 	} else {
615 		VERBOSITY(1, (LOG_INFO, "zone %s read with success",
616 			zone->opts->name));
617 		zone->is_ok = 1;
618 		zone->is_changed = 0;
619 		/* store zone into udb */
620 		if(nsd->db->udb) {
621 			if(!write_zone_to_udb(nsd->db->udb, zone, &mtime,
622 				fname)) {
623 				log_msg(LOG_ERR, "failed to store zone in db");
624 			} else {
625 				VERBOSITY(2, (LOG_INFO, "zone %s written to db",
626 					zone->opts->name));
627 			}
628 		} else {
629 			zone->mtime = mtime;
630 			if(zone->filename)
631 				region_recycle(nsd->db->region, zone->filename,
632 					strlen(zone->filename)+1);
633 			zone->filename = region_strdup(nsd->db->region, fname);
634 			if(zone->logstr)
635 				region_recycle(nsd->db->region, zone->logstr,
636 					strlen(zone->logstr)+1);
637 			zone->logstr = NULL;
638 		}
639 		if(ixfr_create_already_done) {
640 			ixfr_readup_exist(zone, nsd, fname);
641 		} else if(ixfrcr) {
642 			if(!ixfr_create_perform(ixfrcr, zone, 1, nsd, fname,
643 				zone->opts->pattern->ixfr_number)) {
644 				log_msg(LOG_ERR, "failed to create IXFR");
645 			} else {
646 				VERBOSITY(2, (LOG_INFO, "zone %s created IXFR %s.ixfr",
647 					zone->opts->name, fname));
648 			}
649 			ixfr_create_free(ixfrcr);
650 		} else if(zone_is_ixfr_enabled(zone)) {
651 			ixfr_read_from_file(nsd, zone, fname);
652 		}
653 	}
654 	if(taskudb) task_new_soainfo(taskudb, last_task, zone, 0);
655 #ifdef NSEC3
656 	prehash_zone_complete(nsd->db, zone);
657 #endif
658 }
659 
namedb_check_zonefile(struct nsd * nsd,udb_base * taskudb,udb_ptr * last_task,struct zone_options * zopt)660 void namedb_check_zonefile(struct nsd* nsd, udb_base* taskudb,
661 	udb_ptr* last_task, struct zone_options* zopt)
662 {
663 	zone_type* zone;
664 	const dname_type* dname = (const dname_type*)zopt->node.key;
665 	/* find zone to go with it, or create it */
666 	zone = namedb_find_zone(nsd->db, dname);
667 	if(!zone) {
668 		zone = namedb_zone_create(nsd->db, dname, zopt);
669 	}
670 	namedb_read_zonefile(nsd, zone, taskudb, last_task);
671 }
672 
namedb_check_zonefiles(struct nsd * nsd,struct nsd_options * opt,udb_base * taskudb,udb_ptr * last_task)673 void namedb_check_zonefiles(struct nsd* nsd, struct nsd_options* opt,
674 	udb_base* taskudb, udb_ptr* last_task)
675 {
676 	struct zone_options* zo;
677 	/* check all zones in opt, create if not exist in main db */
678 	RBTREE_FOR(zo, struct zone_options*, opt->zone_options) {
679 		namedb_check_zonefile(nsd, taskudb, last_task, zo);
680 		if(nsd->signal_hint_shutdown) break;
681 	}
682 }
683