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