1 /* 2 * dbaccess.c -- access methods for nsd(8) database 3 * 4 * Copyright (c) 2001-2011, 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 #include <stdio.h> /* DEBUG */ 21 22 #include "dns.h" 23 #include "namedb.h" 24 #include "util.h" 25 #include "options.h" 26 27 int 28 namedb_lookup(struct namedb *db, 29 const dname_type *dname, 30 domain_type **closest_match, 31 domain_type **closest_encloser) 32 { 33 return domain_table_search( 34 db->domains, dname, closest_match, closest_encloser); 35 } 36 37 static int 38 read_magic(namedb_type *db) 39 { 40 char buf[NAMEDB_MAGIC_SIZE]; 41 42 if (fread(buf, sizeof(char), sizeof(buf), db->fd) != sizeof(buf)) 43 return 0; 44 45 return memcmp(buf, NAMEDB_MAGIC, NAMEDB_MAGIC_SIZE) == 0; 46 } 47 48 static const dname_type * 49 read_dname(FILE *fd, region_type *region) 50 { 51 uint8_t size; 52 uint8_t temp[MAXDOMAINLEN]; 53 54 if (fread(&size, sizeof(uint8_t), 1, fd) != 1) 55 return NULL; 56 if (fread(temp, sizeof(uint8_t), size, fd) != size) 57 return NULL; 58 59 return dname_make(region, temp, 1); 60 } 61 62 static int 63 read_size(namedb_type *db, uint32_t *result) 64 { 65 if (fread(result, sizeof(*result), 1, db->fd) == 1) { 66 *result = ntohl(*result); 67 return 1; 68 } else { 69 return 0; 70 } 71 } 72 73 static domain_type * 74 read_domain(namedb_type *db, uint32_t domain_count, domain_type **domains) 75 { 76 uint32_t domain_number; 77 78 if (!read_size(db, &domain_number)) 79 return NULL; 80 81 if (domain_number == 0 || domain_number > domain_count) 82 return NULL; 83 84 return domains[domain_number - 1]; 85 } 86 87 static zone_type * 88 read_zone(namedb_type *db, uint32_t zone_count, zone_type **zones) 89 { 90 uint32_t zone_number; 91 92 if (!read_size(db, &zone_number)) 93 return NULL; 94 95 if (zone_number == 0 || zone_number > zone_count) 96 return NULL; 97 98 return zones[zone_number - 1]; 99 } 100 101 static int 102 read_rdata_atom(namedb_type *db, uint16_t type, int index, uint32_t domain_count, domain_type **domains, rdata_atom_type *result) 103 { 104 uint8_t data[65536]; 105 106 if (rdata_atom_is_domain(type, index)) { 107 result->domain = read_domain(db, domain_count, domains); 108 if (!result->domain) 109 return 0; 110 } else { 111 uint16_t size; 112 113 if (fread(&size, sizeof(size), 1, db->fd) != 1) 114 return 0; 115 size = ntohs(size); 116 if (fread(data, sizeof(uint8_t), size, db->fd) != size) 117 return 0; 118 119 result->data = (uint16_t *) region_alloc( 120 db->region, sizeof(uint16_t) + size); 121 memcpy(result->data, &size, sizeof(uint16_t)); 122 memcpy((uint8_t *) result->data + sizeof(uint16_t), data, size); 123 } 124 125 return 1; 126 } 127 128 static rrset_type * 129 read_rrset(namedb_type *db, 130 uint32_t domain_count, domain_type **domains, 131 uint32_t zone_count, zone_type **zones) 132 { 133 rrset_type *rrset; 134 int i, j; 135 domain_type *owner; 136 uint16_t type; 137 uint16_t klass; 138 uint32_t soa_minimum; 139 140 owner = read_domain(db, domain_count, domains); 141 if (!owner) 142 return NULL; 143 144 rrset = (rrset_type *) region_alloc(db->region, sizeof(rrset_type)); 145 146 rrset->zone = read_zone(db, zone_count, zones); 147 if (!rrset->zone) 148 return NULL; 149 150 if (fread(&type, sizeof(type), 1, db->fd) != 1) 151 return NULL; 152 type = ntohs(type); 153 154 if (fread(&klass, sizeof(klass), 1, db->fd) != 1) 155 return NULL; 156 klass = ntohs(klass); 157 158 if (fread(&rrset->rr_count, sizeof(rrset->rr_count), 1, db->fd) != 1) 159 return NULL; 160 rrset->rr_count = ntohs(rrset->rr_count); 161 rrset->rrs = (rr_type *) region_alloc( 162 db->region, rrset->rr_count * sizeof(rr_type)); 163 164 assert(rrset->rr_count > 0); 165 166 for (i = 0; i < rrset->rr_count; ++i) { 167 rr_type *rr = &rrset->rrs[i]; 168 169 rr->owner = owner; 170 rr->type = type; 171 rr->klass = klass; 172 173 if (fread(&rr->rdata_count, sizeof(rr->rdata_count), 1, db->fd) != 1) 174 return NULL; 175 rr->rdata_count = ntohs(rr->rdata_count); 176 rr->rdatas = (rdata_atom_type *) region_alloc( 177 db->region, rr->rdata_count * sizeof(rdata_atom_type)); 178 179 if (fread(&rr->ttl, sizeof(rr->ttl), 1, db->fd) != 1) 180 return NULL; 181 rr->ttl = ntohl(rr->ttl); 182 183 for (j = 0; j < rr->rdata_count; ++j) { 184 if (!read_rdata_atom(db, rr->type, j, domain_count, domains, &rr->rdatas[j])) 185 return NULL; 186 } 187 } 188 189 domain_add_rrset(owner, rrset); 190 191 if (rrset_rrtype(rrset) == TYPE_SOA) { 192 assert(owner == rrset->zone->apex); 193 rrset->zone->soa_rrset = rrset; 194 195 /* BUG #103 add another soa with a tweaked ttl */ 196 rrset->zone->soa_nx_rrset = region_alloc(db->region, sizeof(rrset_type)); 197 rrset->zone->soa_nx_rrset->rrs = 198 region_alloc(db->region, rrset->rr_count * sizeof(rr_type)); 199 200 memcpy(rrset->zone->soa_nx_rrset->rrs, rrset->rrs, sizeof(rr_type)); 201 rrset->zone->soa_nx_rrset->rr_count = 1; 202 rrset->zone->soa_nx_rrset->next = 0; 203 204 /* also add a link to the zone */ 205 rrset->zone->soa_nx_rrset->zone = rrset->zone; 206 207 /* check the ttl and MINIMUM value and set accordinly */ 208 memcpy(&soa_minimum, rdata_atom_data(rrset->rrs->rdatas[6]), 209 rdata_atom_size(rrset->rrs->rdatas[6])); 210 if (rrset->rrs->ttl > ntohl(soa_minimum)) { 211 rrset->zone->soa_nx_rrset->rrs[0].ttl = ntohl(soa_minimum); 212 } 213 214 } else if (owner == rrset->zone->apex 215 && rrset_rrtype(rrset) == TYPE_NS) 216 { 217 rrset->zone->ns_rrset = rrset; 218 } 219 220 if (rrset_rrtype(rrset) == TYPE_RRSIG && owner == rrset->zone->apex) { 221 for (i = 0; i < rrset->rr_count; ++i) { 222 if (rr_rrsig_type_covered(&rrset->rrs[i]) == TYPE_SOA) { 223 rrset->zone->is_secure = 1; 224 break; 225 } 226 } 227 } 228 return rrset; 229 } 230 231 struct namedb * 232 namedb_open (const char *filename, nsd_options_t* opt, size_t num_children) 233 { 234 namedb_type *db; 235 236 /* 237 * Region used to store the loaded database. The region is 238 * freed in namedb_close. 239 */ 240 region_type *db_region; 241 242 /* 243 * Temporary region used while loading domain names from the 244 * database. The region is freed after each time a dname is 245 * read from the database. 246 */ 247 region_type *dname_region; 248 249 /* 250 * Temporary region used to store array of domains and zones 251 * while loading the database. The region is freed before 252 * returning. 253 */ 254 region_type *temp_region; 255 256 uint32_t dname_count; 257 domain_type **domains; /* Indexed by domain number. */ 258 259 uint32_t zone_count; 260 zone_type **zones; /* Indexed by zone number. */ 261 262 uint32_t i; 263 uint32_t rrset_count = 0; 264 uint32_t rr_count = 0; 265 266 rrset_type *rrset; 267 268 DEBUG(DEBUG_DBACCESS, 2, 269 (LOG_INFO, "sizeof(namedb_type) = %lu\n", (unsigned long) sizeof(namedb_type))); 270 DEBUG(DEBUG_DBACCESS, 2, 271 (LOG_INFO, "sizeof(zone_type) = %lu\n", (unsigned long) sizeof(zone_type))); 272 DEBUG(DEBUG_DBACCESS, 2, 273 (LOG_INFO, "sizeof(domain_type) = %lu\n", (unsigned long) sizeof(domain_type))); 274 DEBUG(DEBUG_DBACCESS, 2, 275 (LOG_INFO, "sizeof(rrset_type) = %lu\n", (unsigned long) sizeof(rrset_type))); 276 DEBUG(DEBUG_DBACCESS, 2, 277 (LOG_INFO, "sizeof(rr_type) = %lu\n", (unsigned long) sizeof(rr_type))); 278 DEBUG(DEBUG_DBACCESS, 2, 279 (LOG_INFO, "sizeof(rdata_atom_type) = %lu\n", (unsigned long) sizeof(rdata_atom_type))); 280 DEBUG(DEBUG_DBACCESS, 2, 281 (LOG_INFO, "sizeof(rbnode_t) = %lu\n", (unsigned long) sizeof(rbnode_t))); 282 283 #ifdef USE_MMAP_ALLOC 284 db_region = region_create_custom(mmap_alloc, mmap_free, MMAP_ALLOC_CHUNK_SIZE, 285 MMAP_ALLOC_LARGE_OBJECT_SIZE, MMAP_ALLOC_INITIAL_CLEANUP_SIZE, 1); 286 #else /* !USE_MMAP_ALLOC */ 287 db_region = region_create_custom(xalloc, free, DEFAULT_CHUNK_SIZE, 288 DEFAULT_LARGE_OBJECT_SIZE, DEFAULT_INITIAL_CLEANUP_SIZE, 1); 289 #endif /* !USE_MMAP_ALLOC */ 290 db = (namedb_type *) region_alloc(db_region, sizeof(struct namedb)); 291 db->region = db_region; 292 db->domains = domain_table_create(db->region); 293 db->zones = NULL; 294 db->zone_count = 0; 295 db->filename = region_strdup(db->region, filename); 296 db->crc = 0xffffffff; 297 db->diff_skip = 0; 298 299 if (gettimeofday(&(db->diff_timestamp), NULL) != 0) { 300 log_msg(LOG_ERR, "unable to load %s: cannot initialize" 301 "timestamp", db->filename); 302 region_destroy(db_region); 303 return NULL; 304 } 305 306 /* Open it... */ 307 db->fd = fopen(db->filename, "r"); 308 if (db->fd == NULL) { 309 log_msg(LOG_ERR, "unable to load %s: %s", 310 db->filename, strerror(errno)); 311 region_destroy(db_region); 312 return NULL; 313 } 314 315 if (!read_magic(db)) { 316 log_msg(LOG_ERR, "corrupted database (read magic): %s", db->filename); 317 namedb_close(db); 318 return NULL; 319 } 320 321 if (!read_size(db, &zone_count)) { 322 log_msg(LOG_ERR, "corrupted database (read size): %s", db->filename); 323 namedb_close(db); 324 return NULL; 325 } 326 327 DEBUG(DEBUG_DBACCESS, 1, 328 (LOG_INFO, "Retrieving %lu zones\n", (unsigned long) zone_count)); 329 330 temp_region = region_create(xalloc, free); 331 dname_region = region_create(xalloc, free); 332 333 db->zone_count = zone_count; 334 zones = (zone_type **) region_alloc(temp_region, 335 zone_count * sizeof(zone_type *)); 336 for (i = 0; i < zone_count; ++i) { 337 const dname_type *dname = read_dname(db->fd, dname_region); 338 if (!dname) { 339 log_msg(LOG_ERR, "corrupted database (read dname): %s", db->filename); 340 region_destroy(dname_region); 341 region_destroy(temp_region); 342 namedb_close(db); 343 return NULL; 344 } 345 zones[i] = (zone_type *) region_alloc(db->region, 346 sizeof(zone_type)); 347 zones[i]->next = db->zones; 348 db->zones = zones[i]; 349 zones[i]->apex = domain_table_insert(db->domains, dname); 350 zones[i]->soa_rrset = NULL; 351 zones[i]->soa_nx_rrset = NULL; 352 zones[i]->ns_rrset = NULL; 353 #ifdef NSEC3 354 zones[i]->nsec3_soa_rr = NULL; 355 zones[i]->nsec3_last = NULL; 356 #endif 357 zones[i]->opts = zone_options_find(opt, domain_dname(zones[i]->apex)); 358 zones[i]->number = i + 1; 359 zones[i]->is_secure = 0; 360 zones[i]->updated = 1; 361 zones[i]->is_ok = 0; 362 zones[i]->dirty = region_alloc(db->region, sizeof(uint8_t)*num_children); 363 memset(zones[i]->dirty, 0, sizeof(uint8_t)*num_children); 364 if(!zones[i]->opts) { 365 log_msg(LOG_ERR, "cannot load database. Zone %s in db " 366 "%s, but not in config file (might " 367 "happen if you edited the config " 368 "file). Please rebuild database and " 369 "start again.", 370 dname_to_string(dname, NULL), db->filename); 371 region_destroy(dname_region); 372 region_destroy(temp_region); 373 namedb_close(db); 374 return NULL; 375 } 376 377 region_free_all(dname_region); 378 } 379 380 if (!read_size(db, &dname_count)) { 381 log_msg(LOG_ERR, "corrupted database (read size): %s", db->filename); 382 region_destroy(dname_region); 383 region_destroy(temp_region); 384 namedb_close(db); 385 return NULL; 386 } 387 388 DEBUG(DEBUG_DBACCESS, 1, 389 (LOG_INFO, "Retrieving %lu domain names\n", (unsigned long) dname_count)); 390 391 domains = (domain_type **) region_alloc( 392 temp_region, dname_count * sizeof(domain_type *)); 393 for (i = 0; i < dname_count; ++i) { 394 const dname_type *dname = read_dname(db->fd, dname_region); 395 if (!dname) { 396 log_msg(LOG_ERR, "corrupted database (read dname): %s", db->filename); 397 region_destroy(dname_region); 398 region_destroy(temp_region); 399 namedb_close(db); 400 return NULL; 401 } 402 domains[i] = domain_table_insert(db->domains, dname); 403 region_free_all(dname_region); 404 } 405 406 region_destroy(dname_region); 407 408 #ifndef NDEBUG 409 fprintf(stderr, "database region after loading domain names: "); 410 region_dump_stats(db->region, stderr); 411 fprintf(stderr, "\n"); 412 #endif 413 414 while ((rrset = read_rrset(db, dname_count, domains, zone_count, zones))) { 415 ++rrset_count; 416 rr_count += rrset->rr_count; 417 } 418 419 DEBUG(DEBUG_DBACCESS, 1, 420 (LOG_INFO, "Retrieved %lu RRs in %lu RRsets\n", 421 (unsigned long) rr_count, (unsigned long) rrset_count)); 422 423 region_destroy(temp_region); 424 425 if ((db->crc_pos = ftello(db->fd)) == -1) { 426 log_msg(LOG_ERR, "ftello %s failed: %s", 427 db->filename, strerror(errno)); 428 namedb_close(db); 429 return NULL; 430 } 431 if (!read_size(db, &db->crc)) { 432 log_msg(LOG_ERR, "corrupted database (read size): %s", db->filename); 433 namedb_close(db); 434 return NULL; 435 } 436 if (!read_magic(db)) { 437 log_msg(LOG_ERR, "corrupted database (read magic): %s", db->filename); 438 namedb_close(db); 439 return NULL; 440 } 441 442 fclose(db->fd); 443 db->fd = NULL; 444 445 #ifndef NDEBUG 446 fprintf(stderr, "database region after loading database: "); 447 region_dump_stats(db->region, stderr); 448 fprintf(stderr, "\n"); 449 #endif 450 451 return db; 452 } 453 454 void 455 namedb_close (struct namedb *db) 456 { 457 namedb_fd_close(db); 458 if (db) { 459 region_destroy(db->region); 460 } 461 } 462 463 void 464 namedb_fd_close (struct namedb *db) 465 { 466 if (db && db->fd) { 467 fclose(db->fd); 468 } 469 } 470 471