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 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 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 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 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 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 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 */ 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. */ 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 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* 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 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 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 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 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 * 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 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 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 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 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