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 udb_rrsets = 0; 36 static unsigned 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 accordinly */ 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( 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, udb_rrsets*100/udb_rrset_count)); 197 } 198 } 199 region_free_all(dname_region); 200 udb_ptr_unlink(&urrset, udb); 201 } 202 203 /** recurse read radix from disk. This radix tree is by domain name, so max of 204 * 256 depth, and thus the stack usage is small. */ 205 static void read_zone_recurse(udb_base* udb, namedb_type* db, 206 region_type* dname_region, zone_type* zone, struct udb_radnode_d* node) 207 { 208 if(node->elem.data) { 209 /* pre-order process of node->elem, for radix tree this is 210 * also in-order processing (identical to order tree_next()) */ 211 read_node_elem(udb, db, dname_region, zone, (struct domain_d*) 212 (udb->base + node->elem.data)); 213 } 214 if(node->lookup.data) { 215 uint16_t i; 216 struct udb_radarray_d* a = (struct udb_radarray_d*) 217 (udb->base + node->lookup.data); 218 /* we do not care for what the exact radix key is, we want 219 * to add all of them and the read routine does not need 220 * the radix-key, it has it stored */ 221 for(i=0; i<a->len; i++) { 222 if(a->array[i].node.data) { 223 read_zone_recurse(udb, db, dname_region, zone, 224 (struct udb_radnode_d*)(udb->base + 225 a->array[i].node.data)); 226 } 227 } 228 } 229 } 230 231 /** read zone data */ 232 static void 233 read_zone_data(udb_base* udb, namedb_type* db, region_type* dname_region, 234 udb_ptr* z, zone_type* zone) 235 { 236 udb_ptr dtree; 237 /* recursively read domains, we only read so ptrs stay valid */ 238 udb_ptr_new(&dtree, udb, &ZONE(z)->domains); 239 if(RADTREE(&dtree)->root.data) 240 read_zone_recurse(udb, db, dname_region, zone, 241 (struct udb_radnode_d*) 242 (udb->base + RADTREE(&dtree)->root.data)); 243 udb_ptr_unlink(&dtree, udb); 244 } 245 246 /** create a zone */ 247 zone_type* 248 namedb_zone_create(namedb_type* db, const dname_type* dname, 249 zone_options_t* zo) 250 { 251 zone_type* zone = (zone_type *) region_alloc(db->region, 252 sizeof(zone_type)); 253 zone->node = radname_insert(db->zonetree, dname_name(dname), 254 dname->name_size, zone); 255 assert(zone->node); 256 zone->apex = domain_table_insert(db->domains, dname); 257 zone->apex->usage++; /* the zone.apex reference */ 258 zone->apex->is_apex = 1; 259 zone->soa_rrset = NULL; 260 zone->soa_nx_rrset = NULL; 261 zone->ns_rrset = NULL; 262 #ifdef NSEC3 263 zone->nsec3_param = NULL; 264 zone->nsec3_last = NULL; 265 zone->nsec3tree = NULL; 266 zone->hashtree = NULL; 267 zone->wchashtree = NULL; 268 zone->dshashtree = NULL; 269 #endif 270 zone->opts = zo; 271 zone->is_secure = 0; 272 zone->is_changed = 0; 273 zone->is_ok = 1; 274 return zone; 275 } 276 277 void 278 namedb_zone_delete(namedb_type* db, zone_type* zone) 279 { 280 /* RRs and UDB and NSEC3 and so on must be already deleted */ 281 radix_delete(db->zonetree, zone->node); 282 283 /* see if apex can be deleted */ 284 if(zone->apex) { 285 zone->apex->usage --; 286 if(zone->apex->usage == 0) { 287 /* delete the apex, possibly */ 288 domain_table_deldomain(db, zone->apex); 289 } 290 } 291 292 /* soa_rrset is freed when the SOA was deleted */ 293 if(zone->soa_nx_rrset) { 294 region_recycle(db->region, zone->soa_nx_rrset->rrs, 295 sizeof(rr_type)); 296 region_recycle(db->region, zone->soa_nx_rrset, 297 sizeof(rrset_type)); 298 } 299 #ifdef NSEC3 300 hash_tree_delete(db->region, zone->nsec3tree); 301 hash_tree_delete(db->region, zone->hashtree); 302 hash_tree_delete(db->region, zone->wchashtree); 303 hash_tree_delete(db->region, zone->dshashtree); 304 #endif 305 region_recycle(db->region, zone, sizeof(zone_type)); 306 } 307 308 /** read a zone */ 309 static void 310 read_zone(udb_base* udb, namedb_type* db, nsd_options_t* opt, 311 region_type* dname_region, udb_ptr* z) 312 { 313 /* construct dname */ 314 const dname_type* dname = dname_make(dname_region, ZONE(z)->name, 0); 315 zone_options_t* zo = dname?zone_options_find(opt, dname):NULL; 316 zone_type* zone; 317 if(!dname) return; 318 if(!zo) { 319 /* deleted from the options, remove it from the nsd.db too */ 320 VERBOSITY(2, (LOG_WARNING, "zone %s is deleted", 321 dname_to_string(dname, NULL))); 322 udb_zone_delete(udb, z); 323 region_free_all(dname_region); 324 return; 325 } 326 assert(udb_ptr_get_type(z) == udb_chunk_type_zone); 327 udb_rrsets = 0; 328 udb_rrset_count = ZONE(z)->rrset_count; 329 zone = namedb_zone_create(db, dname, zo); 330 region_free_all(dname_region); 331 read_zone_data(udb, db, dname_region, z, zone); 332 zone->is_changed = (ZONE(z)->is_changed != 0); 333 #ifdef NSEC3 334 prehash_zone_complete(db, zone); 335 #endif 336 } 337 338 /** read zones from nsd.db */ 339 static void 340 read_zones(udb_base* udb, namedb_type* db, nsd_options_t* opt, 341 region_type* dname_region) 342 { 343 udb_ptr ztree, n, z; 344 udb_ptr_init(&z, udb); 345 udb_ptr_new(&ztree, udb, udb_base_get_userdata(udb)); 346 udb_radix_first(udb,&ztree,&n); 347 udb_time = time(NULL); 348 while(n.data) { 349 udb_ptr_set_rptr(&z, udb, &RADNODE(&n)->elem); 350 udb_radix_next(udb, &n); /* store in case n is deleted */ 351 read_zone(udb, db, opt, dname_region, &z); 352 udb_ptr_zero(&z, udb); 353 } 354 udb_ptr_unlink(&ztree, udb); 355 udb_ptr_unlink(&n, udb); 356 udb_ptr_unlink(&z, udb); 357 } 358 359 /** try to read the udb file or fail */ 360 static int 361 try_read_udb(namedb_type* db, int fd, const char* filename, 362 nsd_options_t* opt) 363 { 364 /* 365 * Temporary region used while loading domain names from the 366 * database. The region is freed after each time a dname is 367 * read from the database. 368 */ 369 region_type* dname_region; 370 371 assert(fd != -1); 372 if(!(db->udb=udb_base_create_fd(filename, fd, &namedb_walkfunc, 373 NULL))) { 374 /* fd is closed by failed udb create call */ 375 VERBOSITY(1, (LOG_WARNING, "can not use %s, " 376 "will create anew", filename)); 377 return 0; 378 } 379 /* sanity check if can be opened */ 380 if(udb_base_get_userflags(db->udb) != 0) { 381 log_msg(LOG_WARNING, "%s was not closed properly, it might " 382 "be corrupted, will create anew", filename); 383 udb_base_free(db->udb); 384 db->udb = NULL; 385 return 0; 386 } 387 /* read if it can be opened */ 388 dname_region = region_create(xalloc, free); 389 /* this operation does not fail, we end up with 390 * something, even if that is an empty namedb */ 391 read_zones(db->udb, db, opt, dname_region); 392 region_destroy(dname_region); 393 return 1; 394 } 395 396 struct namedb * 397 namedb_open (const char* filename, nsd_options_t* opt) 398 { 399 namedb_type* db; 400 401 /* 402 * Region used to store the loaded database. The region is 403 * freed in namedb_close. 404 */ 405 region_type* db_region; 406 int fd; 407 408 /* attempt to open, if does not exist, create a new one */ 409 fd = open(filename, O_RDWR); 410 if(fd == -1) { 411 if(errno != ENOENT) { 412 log_msg(LOG_ERR, "%s: %s", filename, strerror(errno)); 413 return NULL; 414 } 415 } 416 417 #ifdef USE_MMAP_ALLOC 418 db_region = region_create_custom(mmap_alloc, mmap_free, MMAP_ALLOC_CHUNK_SIZE, 419 MMAP_ALLOC_LARGE_OBJECT_SIZE, MMAP_ALLOC_INITIAL_CLEANUP_SIZE, 1); 420 #else /* !USE_MMAP_ALLOC */ 421 db_region = region_create_custom(xalloc, free, DEFAULT_CHUNK_SIZE, 422 DEFAULT_LARGE_OBJECT_SIZE, DEFAULT_INITIAL_CLEANUP_SIZE, 1); 423 #endif /* !USE_MMAP_ALLOC */ 424 db = (namedb_type *) region_alloc(db_region, sizeof(struct namedb)); 425 db->region = db_region; 426 db->domains = domain_table_create(db->region); 427 db->zonetree = radix_tree_create(db->region); 428 db->diff_skip = 0; 429 db->diff_pos = 0; 430 431 if (gettimeofday(&(db->diff_timestamp), NULL) != 0) { 432 log_msg(LOG_ERR, "unable to load %s: cannot initialize" 433 "timestamp", filename); 434 region_destroy(db_region); 435 close(fd); 436 return NULL; 437 } 438 439 /* attempt to read the file (if it exists) */ 440 if(fd != -1) { 441 if(!try_read_udb(db, fd, filename, opt)) 442 fd = -1; 443 } 444 /* attempt to create the file (if necessary or failed read) */ 445 if(fd == -1) { 446 if(!(db->udb=udb_base_create_new(filename, &namedb_walkfunc, 447 NULL))) { 448 region_destroy(db_region); 449 return NULL; 450 } 451 if(!udb_dns_init_file(db->udb)) { 452 region_destroy(db->region); 453 return NULL; 454 } 455 } 456 zonec_setup_parser(db); 457 return db; 458 } 459 460 /** the the file mtime stat (or nonexist or error) */ 461 static int 462 file_get_mtime(const char* file, time_t* mtime, int* nonexist) 463 { 464 struct stat s; 465 if(stat(file, &s) != 0) { 466 *mtime = 0; 467 *nonexist = (errno == ENOENT); 468 return 0; 469 } 470 *nonexist = 0; 471 *mtime = s.st_mtime; 472 return 1; 473 } 474 475 void 476 namedb_read_zonefile(struct nsd* nsd, struct zone* zone, udb_base* taskudb, 477 udb_ptr* last_task) 478 { 479 time_t mtime = 0; 480 int nonexist = 0; 481 unsigned int errors; 482 const char* fname; 483 if(!nsd->db || !nsd->db->udb || !zone || !zone->opts || !zone->opts->pattern->zonefile) 484 return; 485 fname = config_make_zonefile(zone->opts, nsd); 486 if(!file_get_mtime(fname, &mtime, &nonexist)) { 487 if(nonexist) { 488 VERBOSITY(2, (LOG_INFO, "zonefile %s does not exist", 489 fname)); 490 } else 491 log_msg(LOG_ERR, "zonefile %s: %s", 492 fname, strerror(errno)); 493 if(taskudb) task_new_soainfo(taskudb, last_task, zone, 0); 494 return; 495 } else { 496 const char* zone_fname = udb_zone_get_file_str(nsd->db->udb, 497 dname_name(domain_dname(zone->apex)), domain_dname( 498 zone->apex)->name_size); 499 /* if no zone_fname, then it was acquired in zone transfer, 500 * see if the file is newer than the zone transfer 501 * (regardless if this is a different file), because the 502 * zone transfer is a different content source too */ 503 if(!zone_fname && udb_zone_get_mtime(nsd->db->udb, 504 dname_name(domain_dname(zone->apex)), domain_dname( 505 zone->apex)->name_size) >= (uint64_t)mtime) { 506 VERBOSITY(3, (LOG_INFO, "zonefile %s is older than " 507 "zone transfer in memory", fname)); 508 return; 509 510 /* if zone_fname, then the file was acquired from reading it, 511 * and see if filename changed or mtime newer to read it */ 512 } else if(zone_fname && fname && 513 strcmp(zone_fname, fname) == 0 && 514 udb_zone_get_mtime(nsd->db->udb, dname_name(domain_dname( 515 zone->apex)), domain_dname(zone->apex)->name_size) 516 >= (uint64_t)mtime) { 517 VERBOSITY(3, (LOG_INFO, "zonefile %s is not modified", 518 fname)); 519 return; 520 } 521 } 522 523 assert(parser); 524 /* wipe zone from memory */ 525 #ifdef NSEC3 526 nsec3_hash_tree_clear(zone); 527 #endif 528 delete_zone_rrs(nsd->db, zone); 529 #ifdef NSEC3 530 nsec3_clear_precompile(nsd->db, zone); 531 zone->nsec3_param = NULL; 532 #endif /* NSEC3 */ 533 errors = zonec_read(zone->opts->name, fname, zone); 534 if(errors > 0) { 535 region_type* dname_region; 536 udb_ptr z; 537 log_msg(LOG_ERR, "zone %s file %s read with %u errors", 538 zone->opts->name, fname, errors); 539 /* wipe (partial) zone from memory */ 540 zone->is_ok = 1; 541 #ifdef NSEC3 542 nsec3_hash_tree_clear(zone); 543 #endif 544 delete_zone_rrs(nsd->db, zone); 545 #ifdef NSEC3 546 nsec3_clear_precompile(nsd->db, zone); 547 zone->nsec3_param = NULL; 548 #endif /* NSEC3 */ 549 /* see if we can revert to the udb stored version */ 550 if(!udb_zone_search(nsd->db->udb, &z, dname_name(domain_dname( 551 zone->apex)), domain_dname(zone->apex)->name_size)) { 552 /* tell that zone contents has been lost */ 553 if(taskudb) task_new_soainfo(taskudb, last_task, zone, 0); 554 return; 555 } 556 /* read from udb */ 557 dname_region = region_create(xalloc, free); 558 udb_rrsets = 0; 559 udb_rrset_count = ZONE(&z)->rrset_count; 560 udb_time = time(NULL); 561 read_zone_data(nsd->db->udb, nsd->db, dname_region, &z, zone); 562 region_destroy(dname_region); 563 udb_ptr_unlink(&z, nsd->db->udb); 564 } else { 565 VERBOSITY(1, (LOG_INFO, "zone %s read with no errors", 566 zone->opts->name)); 567 zone->is_ok = 1; 568 zone->is_changed = 0; 569 /* store zone into udb */ 570 if(!write_zone_to_udb(nsd->db->udb, zone, mtime, fname)) { 571 log_msg(LOG_ERR, "failed to store zone in db"); 572 } else { 573 VERBOSITY(2, (LOG_INFO, "zone %s written to db", 574 zone->opts->name)); 575 } 576 } 577 if(taskudb) task_new_soainfo(taskudb, last_task, zone, 0); 578 #ifdef NSEC3 579 prehash_zone_complete(nsd->db, zone); 580 #endif 581 } 582 583 void namedb_check_zonefile(struct nsd* nsd, udb_base* taskudb, 584 udb_ptr* last_task, zone_options_t* zopt) 585 { 586 zone_type* zone; 587 const dname_type* dname = (const dname_type*)zopt->node.key; 588 /* find zone to go with it, or create it */ 589 zone = namedb_find_zone(nsd->db, dname); 590 if(!zone) { 591 zone = namedb_zone_create(nsd->db, dname, zopt); 592 } 593 namedb_read_zonefile(nsd, zone, taskudb, last_task); 594 } 595 596 void namedb_check_zonefiles(struct nsd* nsd, nsd_options_t* opt, 597 udb_base* taskudb, udb_ptr* last_task) 598 { 599 zone_options_t* zo; 600 /* check all zones in opt, create if not exist in main db */ 601 RBTREE_FOR(zo, zone_options_t*, opt->zone_options) { 602 namedb_check_zonefile(nsd, taskudb, last_task, zo); 603 } 604 } 605