1 /* 2 * difffile.c - DIFF file handling source code. Read and write diff files. 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 #include <assert.h> 12 #include <string.h> 13 #include <unistd.h> 14 #include <stdlib.h> 15 #include <errno.h> 16 #include "difffile.h" 17 #include "util.h" 18 #include "packet.h" 19 #include "rdata.h" 20 #include "nsec3.h" 21 22 static int 23 write_32(FILE *out, uint32_t val) 24 { 25 val = htonl(val); 26 return write_data(out, &val, sizeof(val)); 27 } 28 29 static int 30 write_16(FILE *out, uint16_t val) 31 { 32 val = htons(val); 33 return write_data(out, &val, sizeof(val)); 34 } 35 36 static int 37 write_8(FILE *out, uint8_t val) 38 { 39 return write_data(out, &val, sizeof(val)); 40 } 41 42 static int 43 write_str(FILE *out, const char* str) 44 { 45 uint32_t len = strlen(str); 46 if(!write_32(out, len)) 47 return 0; 48 return write_data(out, str, len); 49 } 50 51 void 52 diff_write_packet(const char* zone, uint32_t new_serial, uint16_t id, 53 uint32_t seq_nr, uint8_t* data, size_t len, nsd_options_t* opt) 54 { 55 const char* filename = opt->difffile; 56 struct timeval tv; 57 FILE *df; 58 uint32_t file_len = sizeof(uint32_t) + strlen(zone) + 59 sizeof(new_serial) + sizeof(id) + sizeof(seq_nr) + len; 60 61 if (gettimeofday(&tv, NULL) != 0) { 62 log_msg(LOG_ERR, "could not set timestamp for %s: %s", 63 filename, strerror(errno)); 64 return; 65 } 66 67 df = fopen(filename, "a"); 68 if(!df) { 69 log_msg(LOG_ERR, "could not open file %s for append: %s", 70 filename, strerror(errno)); 71 return; 72 } 73 74 if(!write_32(df, DIFF_PART_IXFR) || 75 !write_32(df, (uint32_t) tv.tv_sec) || 76 !write_32(df, (uint32_t) tv.tv_usec) || 77 !write_32(df, file_len) || 78 !write_str(df, zone) || 79 !write_32(df, new_serial) || 80 !write_16(df, id) || 81 !write_32(df, seq_nr) || 82 !write_data(df, data, len) || 83 !write_32(df, file_len)) 84 { 85 log_msg(LOG_ERR, "could not write to file %s: %s", 86 filename, strerror(errno)); 87 } 88 fflush(df); 89 fclose(df); 90 } 91 92 void 93 diff_write_commit(const char* zone, uint32_t old_serial, 94 uint32_t new_serial, uint16_t id, uint32_t num_parts, 95 uint8_t commit, const char* log_str, nsd_options_t* opt) 96 { 97 const char* filename = opt->difffile; 98 struct timeval tv; 99 FILE *df; 100 uint32_t len; 101 102 if (gettimeofday(&tv, NULL) != 0) { 103 log_msg(LOG_ERR, "could not set timestamp for %s: %s", 104 filename, strerror(errno)); 105 return; 106 } 107 108 df = fopen(filename, "a"); 109 if(!df) { 110 log_msg(LOG_ERR, "could not open file %s for append: %s", 111 filename, strerror(errno)); 112 return; 113 } 114 115 len = strlen(zone) + sizeof(len) + sizeof(old_serial) + 116 sizeof(new_serial) + sizeof(id) + sizeof(num_parts) + 117 sizeof(commit) + strlen(log_str) + sizeof(len); 118 119 if(!write_32(df, DIFF_PART_SURE) || 120 !write_32(df, (uint32_t) tv.tv_sec) || 121 !write_32(df, (uint32_t) tv.tv_usec) || 122 !write_32(df, len) || 123 !write_str(df, zone) || 124 !write_32(df, old_serial) || 125 !write_32(df, new_serial) || 126 !write_16(df, id) || 127 !write_32(df, num_parts) || 128 !write_8(df, commit) || 129 !write_str(df, log_str) || 130 !write_32(df, len)) 131 { 132 log_msg(LOG_ERR, "could not write to file %s: %s", 133 filename, strerror(errno)); 134 } 135 fflush(df); 136 fclose(df); 137 } 138 139 /* 140 * Checksum to signal no data change occured (for example, by a 141 * zonec run. 142 */ 143 int 144 db_crc_different(namedb_type* db) 145 { 146 FILE *fd = fopen(db->filename, "r"); 147 uint32_t crc_file; 148 char buf[NAMEDB_MAGIC_SIZE]; 149 if(fd == NULL) { 150 log_msg(LOG_ERR, "unable to load %s: %s", 151 db->filename, strerror(errno)); 152 return -1; 153 } 154 155 /* seek to position of CRC, check it and magic no */ 156 if(fseeko(fd, db->crc_pos, SEEK_SET)==-1) { 157 log_msg(LOG_ERR, "unable to fseeko %s: %s. db changed?", 158 db->filename, strerror(errno)); 159 fclose(fd); 160 return -1; 161 } 162 163 if(fread(&crc_file, sizeof(crc_file), 1, fd) != 1) { 164 if(!feof(fd)) 165 log_msg(LOG_ERR, "could not read %s CRC: %s. " 166 "db changed?", db->filename, strerror(errno)); 167 fclose(fd); 168 return -1; 169 } 170 crc_file = ntohl(crc_file); 171 172 if(fread(buf, sizeof(char), sizeof(buf), fd) != sizeof(buf)) { 173 if(!feof(fd)) 174 log_msg(LOG_ERR, "could not read %s magic: %s. " 175 "db changed?", db->filename, strerror(errno)); 176 fclose(fd); 177 return -1; 178 } 179 if(memcmp(buf, NAMEDB_MAGIC, NAMEDB_MAGIC_SIZE) != 0) { 180 fclose(fd); 181 return -1; 182 } 183 184 fclose(fd); 185 186 if(db->crc == crc_file) 187 return 0; 188 return 1; 189 } 190 191 int 192 diff_read_32(FILE *in, uint32_t* result) 193 { 194 if (fread(result, sizeof(*result), 1, in) == 1) { 195 *result = ntohl(*result); 196 return 1; 197 } else { 198 return 0; 199 } 200 } 201 202 int 203 diff_read_16(FILE *in, uint16_t* result) 204 { 205 if (fread(result, sizeof(*result), 1, in) == 1) { 206 *result = ntohs(*result); 207 return 1; 208 } else { 209 return 0; 210 } 211 } 212 213 int 214 diff_read_8(FILE *in, uint8_t* result) 215 { 216 if (fread(result, sizeof(*result), 1, in) == 1) { 217 return 1; 218 } else { 219 return 0; 220 } 221 } 222 223 int 224 diff_read_str(FILE* in, char* buf, size_t len) 225 { 226 uint32_t disklen; 227 if(!diff_read_32(in, &disklen)) 228 return 0; 229 if(disklen >= len) 230 return 0; 231 if(fread(buf, disklen, 1, in) != 1) 232 return 0; 233 buf[disklen] = 0; 234 return 1; 235 } 236 237 static void 238 add_rdata_to_recyclebin(namedb_type* db, rr_type* rr) 239 { 240 /* add rdatas to recycle bin. */ 241 size_t i; 242 for(i=0; i<rr->rdata_count; i++) 243 { 244 if(!rdata_atom_is_domain(rr->type, i)) 245 region_recycle(db->region, rr->rdatas[i].data, 246 rdata_atom_size(rr->rdatas[i]) 247 + sizeof(uint16_t)); 248 } 249 region_recycle(db->region, rr->rdatas, 250 sizeof(rdata_atom_type)*rr->rdata_count); 251 } 252 253 /* this routine determines if below a domain there exist names with 254 * data (is_existing) or no names below the domain have data. 255 */ 256 static int 257 has_data_below(domain_type* top) 258 { 259 domain_type* d = top; 260 assert(d != NULL); 261 /* in the canonical ordering subdomains are after this name */ 262 d = domain_next(d); 263 while(d != NULL && dname_is_subdomain(domain_dname(d), domain_dname(top))) { 264 if(d->is_existing) 265 return 1; 266 d = domain_next(d); 267 } 268 return 0; 269 } 270 271 272 /* this routine makes empty terminals non-existent. 273 * @domain the lowest empty terminal 274 * @ce the closest encloser 275 */ 276 static domain_type* 277 rrset_delete_empty_terminals(domain_type* domain, domain_type* ce) 278 { 279 assert(domain); 280 if (domain->rrsets == 0) { 281 /* if there is no data below it, it becomes non existing. 282 also empty nonterminals above it become nonexisting */ 283 /* check for data below this node. */ 284 if(!has_data_below(domain)) { 285 /* nonexist this domain and all parent empty nonterminals */ 286 domain_type* p = domain; 287 while(p != NULL && p->rrsets == 0) { 288 if(p == ce || has_data_below(p)) 289 return p; 290 p->is_existing = 0; 291 p = p->parent; 292 } 293 } 294 } 295 return NULL; 296 } 297 298 299 static domain_type* 300 rrset_delete(namedb_type* db, domain_type* domain, rrset_type* rrset) 301 { 302 int i; 303 /* find previous */ 304 rrset_type** pp = &domain->rrsets; 305 while(*pp && *pp != rrset) { 306 pp = &( (*pp)->next ); 307 } 308 if(!*pp) { 309 /* rrset does not exist for domain */ 310 return NULL; 311 } 312 *pp = rrset->next; 313 314 DEBUG(DEBUG_XFRD,2, (LOG_INFO, "delete rrset of %s type %s", 315 dname_to_string(domain_dname(domain),0), 316 rrtype_to_string(rrset_rrtype(rrset)))); 317 318 /* is this a SOA rrset ? */ 319 if(rrset->zone->soa_rrset == rrset) { 320 rrset->zone->soa_rrset = 0; 321 rrset->zone->updated = 1; 322 domain->has_SOA = 0; 323 } 324 if(rrset->zone->ns_rrset == rrset) { 325 rrset->zone->ns_rrset = 0; 326 } 327 if(domain == rrset->zone->apex && rrset_rrtype(rrset) == TYPE_RRSIG) { 328 for (i = 0; i < rrset->rr_count; ++i) { 329 if (rr_rrsig_type_covered(&rrset->rrs[i]) == TYPE_DNSKEY) { 330 rrset->zone->is_secure = 0; 331 break; 332 } 333 } 334 } 335 336 #ifdef NSEC3 337 #ifndef FULL_PREHASH 338 if (rrset->rrs[0].type == TYPE_NSEC3) { 339 namedb_del_nsec3_domain(db, domain, rrset->zone); 340 } 341 #endif /* !FULL_PREHASH */ 342 #endif /* NSEC3 */ 343 344 /* recycle the memory space of the rrset */ 345 for (i = 0; i < rrset->rr_count; ++i) 346 add_rdata_to_recyclebin(db, &rrset->rrs[i]); 347 region_recycle(db->region, rrset->rrs, 348 sizeof(rr_type) * rrset->rr_count); 349 rrset->rr_count = 0; 350 region_recycle(db->region, rrset, sizeof(rrset_type)); 351 352 /* is the node now an empty node (completely deleted) */ 353 if (domain->rrsets == 0) { 354 return domain; 355 } 356 return NULL; 357 } 358 359 static int 360 rdatas_equal(rdata_atom_type *a, rdata_atom_type *b, int num, uint16_t type) 361 { 362 int k; 363 for(k = 0; k < num; k++) 364 { 365 if(rdata_atom_is_domain(type, k)) { 366 if(dname_compare(domain_dname(a[k].domain), 367 domain_dname(b[k].domain))!=0) 368 return 0; 369 } else { 370 /* check length */ 371 if(a[k].data[0] != b[k].data[0]) 372 return 0; 373 /* check data */ 374 if(memcmp(a[k].data+1, b[k].data+1, a[k].data[0])!=0) 375 return 0; 376 } 377 } 378 return 1; 379 } 380 381 static int 382 find_rr_num(rrset_type* rrset, 383 uint16_t type, uint16_t klass, 384 rdata_atom_type *rdatas, ssize_t rdata_num) 385 { 386 int i; 387 388 for(i=0; i < rrset->rr_count; ++i) { 389 if(rrset->rrs[i].type == type && 390 rrset->rrs[i].klass == klass && 391 rrset->rrs[i].rdata_count == rdata_num && 392 rdatas_equal(rdatas, rrset->rrs[i].rdatas, rdata_num, type)) 393 { 394 return i; 395 } 396 } 397 398 return -1; 399 } 400 401 static int 402 delete_RR(namedb_type* db, const dname_type* dname, 403 uint16_t type, uint16_t klass, 404 domain_type* prevdomain, 405 buffer_type* packet, size_t rdatalen, zone_type *zone, 406 region_type* temp_region, int is_axfr) 407 { 408 domain_type *domain; 409 rrset_type *rrset; 410 domain = domain_table_find(db->domains, dname); 411 if(!domain) { 412 log_msg(LOG_WARNING, "diff: domain %s does not exist", 413 dname_to_string(dname,0)); 414 buffer_skip(packet, rdatalen); 415 return 1; /* not fatal error */ 416 } 417 rrset = domain_find_rrset(domain, zone, type); 418 if(!rrset) { 419 log_msg(LOG_WARNING, "diff: rrset %s does not exist", 420 dname_to_string(dname,0)); 421 buffer_skip(packet, rdatalen); 422 return 1; /* not fatal error */ 423 } else { 424 /* find the RR in the rrset */ 425 domain_table_type *temptable; 426 rdata_atom_type *rdatas; 427 ssize_t rdata_num; 428 int rrnum; 429 temptable = domain_table_create(temp_region); 430 /* This will ensure that the dnames in rdata are 431 * normalized, conform RFC 4035, section 6.2 432 */ 433 rdata_num = rdata_wireformat_to_rdata_atoms( 434 temp_region, temptable, type, rdatalen, packet, &rdatas); 435 if(rdata_num == -1) { 436 log_msg(LOG_ERR, "diff: bad rdata for %s", 437 dname_to_string(dname,0)); 438 return 0; 439 } 440 rrnum = find_rr_num(rrset, type, klass, rdatas, rdata_num); 441 if(rrnum == -1) { 442 log_msg(LOG_WARNING, "diff: RR %s does not exist", 443 dname_to_string(dname,0)); 444 return 1; /* not fatal error */ 445 } 446 #ifdef NSEC3 447 #ifndef FULL_PREHASH 448 if (is_axfr == 0) { 449 struct domain *parent = domain; 450 do { 451 if (0 != namedb_add_nsec3_mod_domain(db, 452 parent)) { 453 return 0; 454 } 455 parent = parent->parent; 456 } while (parent != zone->apex->parent); 457 } 458 #else 459 (void)is_axfr; 460 #endif /* !FULL_PREHASH */ 461 #endif /* NSEC3 */ 462 463 if(rrset->rr_count == 1) { 464 /* delete entire rrset */ 465 domain = rrset_delete(db, domain, rrset); 466 if (domain && domain != prevdomain && !domain->nextdiff) { 467 /* this domain is not yet in the diff chain */ 468 prevdomain->nextdiff = domain; 469 } 470 } else { 471 /* swap out the bad RR and decrease the count */ 472 rr_type* rrs_orig = rrset->rrs; 473 add_rdata_to_recyclebin(db, &rrset->rrs[rrnum]); 474 if(rrnum < rrset->rr_count-1) 475 rrset->rrs[rrnum] = rrset->rrs[rrset->rr_count-1]; 476 memset(&rrset->rrs[rrset->rr_count-1], 0, sizeof(rr_type)); 477 /* realloc the rrs array one smaller */ 478 rrset->rrs = region_alloc_init(db->region, rrs_orig, 479 sizeof(rr_type) * (rrset->rr_count-1)); 480 if(!rrset->rrs) { 481 log_msg(LOG_ERR, "out of memory, %s:%d", __FILE__, __LINE__); 482 exit(1); 483 } 484 region_recycle(db->region, rrs_orig, 485 sizeof(rr_type) * rrset->rr_count); 486 rrset->rr_count --; 487 } 488 } 489 return 1; 490 } 491 492 static int 493 add_RR(namedb_type* db, const dname_type* dname, 494 uint16_t type, uint16_t klass, uint32_t ttl, 495 buffer_type* packet, size_t rdatalen, zone_type *zone, 496 int is_axfr) 497 { 498 domain_type* domain; 499 rrset_type* rrset; 500 rdata_atom_type *rdatas; 501 rr_type *rrs_old; 502 ssize_t rdata_num; 503 int rrnum; 504 domain = domain_table_find(db->domains, dname); 505 if(!domain) { 506 /* create the domain */ 507 domain = domain_table_insert(db->domains, dname); 508 } 509 rrset = domain_find_rrset(domain, zone, type); 510 if(!rrset) { 511 /* create the rrset */ 512 rrset = region_alloc(db->region, sizeof(rrset_type)); 513 if(!rrset) { 514 log_msg(LOG_ERR, "out of memory, %s:%d", __FILE__, __LINE__); 515 exit(1); 516 } 517 rrset->zone = zone; 518 rrset->rrs = 0; 519 rrset->rr_count = 0; 520 domain_add_rrset(domain, rrset); 521 } 522 523 /* dnames in rdata are normalized, conform RFC 4035, 524 * Section 6.2 525 */ 526 rdata_num = rdata_wireformat_to_rdata_atoms( 527 db->region, db->domains, type, rdatalen, packet, &rdatas); 528 if(rdata_num == -1) { 529 log_msg(LOG_ERR, "diff: bad rdata for %s", 530 dname_to_string(dname,0)); 531 return 0; 532 } 533 rrnum = find_rr_num(rrset, type, klass, rdatas, rdata_num); 534 if(rrnum != -1) { 535 DEBUG(DEBUG_XFRD, 2, (LOG_ERR, "diff: RR %s already exists", 536 dname_to_string(dname,0))); 537 /* ignore already existing RR: lenient accepting of messages */ 538 return 1; 539 } 540 541 /* re-alloc the rrs and add the new */ 542 rrs_old = rrset->rrs; 543 rrset->rrs = region_alloc(db->region, 544 (rrset->rr_count+1) * sizeof(rr_type)); 545 if(!rrset->rrs) { 546 log_msg(LOG_ERR, "out of memory, %s:%d", __FILE__, __LINE__); 547 exit(1); 548 } 549 if(rrs_old) 550 memcpy(rrset->rrs, rrs_old, rrset->rr_count * sizeof(rr_type)); 551 region_recycle(db->region, rrs_old, sizeof(rr_type) * rrset->rr_count); 552 rrset->rr_count ++; 553 554 rrset->rrs[rrset->rr_count - 1].owner = domain; 555 rrset->rrs[rrset->rr_count - 1].rdatas = rdatas; 556 rrset->rrs[rrset->rr_count - 1].ttl = ttl; 557 rrset->rrs[rrset->rr_count - 1].type = type; 558 rrset->rrs[rrset->rr_count - 1].klass = klass; 559 rrset->rrs[rrset->rr_count - 1].rdata_count = rdata_num; 560 561 /* see if it is a SOA */ 562 if(domain == zone->apex) { 563 if(type == TYPE_SOA) { 564 uint32_t soa_minimum; 565 zone->soa_rrset = rrset; 566 zone->updated = 1; 567 /* BUG #103 tweaked SOA ttl value */ 568 if(zone->soa_nx_rrset == 0) { 569 zone->soa_nx_rrset = region_alloc(db->region, 570 sizeof(rrset_type)); 571 if(!zone->soa_nx_rrset) { 572 log_msg(LOG_ERR, "out of memory, %s:%d", 573 __FILE__, __LINE__); 574 exit(1); 575 } 576 zone->soa_nx_rrset->rr_count = 1; 577 zone->soa_nx_rrset->next = 0; 578 zone->soa_nx_rrset->zone = zone; 579 zone->soa_nx_rrset->rrs = region_alloc(db->region, 580 sizeof(rr_type)); 581 if(!zone->soa_nx_rrset->rrs) { 582 log_msg(LOG_ERR, "out of memory, %s:%d", 583 __FILE__, __LINE__); 584 exit(1); 585 } 586 } 587 memcpy(zone->soa_nx_rrset->rrs, rrset->rrs, sizeof(rr_type)); 588 memcpy(&soa_minimum, rdata_atom_data(rrset->rrs->rdatas[6]), 589 rdata_atom_size(rrset->rrs->rdatas[6])); 590 if (rrset->rrs->ttl > ntohl(soa_minimum)) { 591 rrset->zone->soa_nx_rrset->rrs[0].ttl = ntohl(soa_minimum); 592 } 593 domain->has_SOA = 1; 594 } 595 if(type == TYPE_NS) { 596 zone->ns_rrset = rrset; 597 } 598 if(type == TYPE_RRSIG) { 599 int i; 600 for (i = 0; i < rrset->rr_count; ++i) { 601 if (rr_rrsig_type_covered(&rrset->rrs[i]) == TYPE_DNSKEY) { 602 zone->is_secure = 1; 603 break; 604 } 605 } 606 } 607 } 608 609 #ifdef NSEC3 610 #ifndef FULL_PREHASH 611 if ((type == TYPE_NSEC3) && 612 (rrset->rr_count == 1)) { 613 /* NSEC3 RRset just added */ 614 if (0 != namedb_add_nsec3_domain(db, domain, zone)) 615 return 0; 616 } 617 if (is_axfr == 0) { 618 struct domain *parent = domain; 619 do { 620 if (0 != namedb_add_nsec3_mod_domain(db, parent)) 621 return 0; 622 parent = parent->parent; 623 } while (parent != zone->apex->parent); 624 } 625 #else 626 (void)is_axfr; 627 #endif /* !FULL_PREHASH */ 628 #endif /* NSEC3 */ 629 630 return 1; 631 } 632 633 static zone_type* 634 find_zone(namedb_type* db, const dname_type* zone_name, nsd_options_t* opt, 635 size_t child_count) 636 { 637 domain_type *domain; 638 zone_type* zone; 639 domain = domain_table_find(db->domains, zone_name); 640 if(!domain) { 641 DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfr: creating domain %s", 642 dname_to_string(zone_name,0))); 643 /* create the zone and domain of apex (zone has config options) */ 644 domain = domain_table_insert(db->domains, zone_name); 645 } else { 646 /* O(1) if SOA exists */ 647 zone = domain_find_zone(domain); 648 /* if domain was empty (no rrsets, empty zone) search in zonelist */ 649 /* check apex to make sure we don't find a parent zone */ 650 if(!zone || zone->apex != domain) 651 zone = namedb_find_zone(db, domain); 652 if(zone) { 653 assert(zone->apex == domain); 654 return zone; 655 } 656 } 657 /* create the zone */ 658 DEBUG(DEBUG_XFRD,1, (LOG_INFO, "xfr: creating zone_type %s", 659 dname_to_string(zone_name,0))); 660 zone = (zone_type *) region_alloc(db->region, sizeof(zone_type)); 661 if(!zone) { 662 log_msg(LOG_ERR, "out of memory, %s:%d", __FILE__, __LINE__); 663 exit(1); 664 } 665 zone->next = db->zones; 666 db->zones = zone; 667 db->zone_count++; 668 zone->apex = domain; 669 zone->soa_rrset = 0; 670 zone->soa_nx_rrset = 0; 671 zone->ns_rrset = 0; 672 #ifdef NSEC3 673 zone->nsec3_soa_rr = NULL; 674 zone->nsec3_last = NULL; 675 #endif 676 zone->dirty = region_alloc(db->region, sizeof(uint8_t)*child_count); 677 if(!zone->dirty) { 678 log_msg(LOG_ERR, "out of memory, %s:%d", __FILE__, __LINE__); 679 exit(1); 680 } 681 memset(zone->dirty, 0, sizeof(uint8_t)*child_count); 682 zone->opts = zone_options_find(opt, domain_dname(zone->apex)); 683 if(!zone->opts) { 684 log_msg(LOG_ERR, "xfr: zone %s not in config.", 685 dname_to_string(zone_name,0)); 686 return 0; 687 } 688 #ifdef NSEC3 689 #ifndef FULL_PREHASH 690 zone->nsec3_domains = NULL; 691 692 if (0 != zone_nsec3_domains_create(db, zone)) { 693 log_msg(LOG_ERR, 694 "xfr: zone NSEC3 domains " 695 "memory allocation failure"); 696 return 0; 697 } 698 #endif /* !FULL_PREHASH */ 699 #endif /* NSEC3 */ 700 zone->number = db->zone_count; 701 zone->is_secure = 0; 702 zone->updated = 1; 703 zone->is_ok = 0; 704 return zone; 705 } 706 707 static void 708 delete_zone_rrs(namedb_type* db, zone_type* zone) 709 { 710 rrset_type *rrset; 711 domain_type *domain = zone->apex; 712 domain_type *next = NULL; 713 zone->updated = 1; 714 #ifdef NSEC3 715 #ifndef FULL_PREHASH 716 zone_nsec3_domains_destroy(db, zone); 717 #endif /* !FULL_PREHASH */ 718 #endif /* NSEC3 */ 719 720 /* go through entire tree below the zone apex (incl subzones) */ 721 while(domain && dname_is_subdomain( 722 domain_dname(domain), domain_dname(zone->apex))) 723 { 724 DEBUG(DEBUG_XFRD,2, (LOG_INFO, "delete zone visit %s", 725 dname_to_string(domain_dname(domain),0))); 726 /* delete all rrsets of the zone */ 727 while((rrset = domain_find_any_rrset(domain, zone))) { 728 (void)rrset_delete(db, domain, rrset); 729 } 730 next = domain_next(domain); 731 domain->nextdiff = next; 732 domain = next; 733 } 734 #ifdef NSEC3 735 #ifndef FULL_PREHASH 736 if (0 != zone_nsec3_domains_create(db, zone)) { 737 log_msg(LOG_ERR, 738 "Zone %s: unable to create zone NSEC3 prehash table", 739 dname_to_string(domain_dname(zone->apex), 740 NULL)); 741 } 742 #endif /* !FULL_PREHASH */ 743 #endif /* NSEC3 */ 744 745 DEBUG(DEBUG_XFRD, 1, (LOG_INFO, "axfrdel: recyclebin holds %lu bytes", 746 (unsigned long) region_get_recycle_size(db->region))); 747 #ifndef NDEBUG 748 if(nsd_debug_level >= 1) 749 region_log_stats(db->region); 750 #endif 751 752 assert(zone->soa_rrset == 0); 753 /* keep zone->soa_nx_rrset alloced */ 754 assert(zone->ns_rrset == 0); 755 assert(zone->is_secure == 0); 756 assert(zone->updated == 1); 757 } 758 759 /* fix empty terminals */ 760 static void 761 fix_empty_terminals(zone_type* zone_db) 762 { 763 domain_type* domain = zone_db->apex, *ce = NULL, *next = NULL; 764 while (domain) { 765 ce = rrset_delete_empty_terminals(domain, ce); 766 next = domain->nextdiff; 767 domain->nextdiff = NULL; 768 domain = next; 769 } 770 } 771 772 /* return value 0: syntaxerror,badIXFR, 1:OK, 2:done_and_skip_it */ 773 static int 774 apply_ixfr(namedb_type* db, FILE *in, const off_t* startpos, 775 const char* zone, uint32_t serialno, nsd_options_t* opt, 776 uint16_t id, uint32_t seq_nr, uint32_t seq_total, 777 int* is_axfr, int* delete_mode, int* rr_count, 778 size_t child_count) 779 { 780 uint32_t filelen, msglen, pkttype, timestamp[2]; 781 int qcount, ancount, counter; 782 buffer_type* packet; 783 region_type* region; 784 int i; 785 uint16_t rrlen; 786 const dname_type *dname_zone, *dname; 787 zone_type* zone_db; 788 domain_type* last_in_list; 789 char file_zone_name[3072]; 790 uint32_t file_serial, file_seq_nr; 791 uint16_t file_id; 792 off_t mempos; 793 794 memmove(&mempos, startpos, sizeof(off_t)); 795 if(fseeko(in, mempos, SEEK_SET) == -1) { 796 log_msg(LOG_INFO, "could not fseeko: %s.", strerror(errno)); 797 return 0; 798 } 799 /* read ixfr packet RRs and apply to in memory db */ 800 801 if(!diff_read_32(in, &pkttype) || pkttype != DIFF_PART_IXFR) { 802 log_msg(LOG_ERR, "could not read type or wrong type"); 803 return 0; 804 } 805 if(!diff_read_32(in, ×tamp[0]) || 806 !diff_read_32(in, ×tamp[1])) { 807 log_msg(LOG_ERR, "could not read timestamp"); 808 return 0; 809 } 810 811 if(!diff_read_32(in, &filelen)) { 812 log_msg(LOG_ERR, "could not read len"); 813 return 0; 814 } 815 816 /* read header */ 817 if(filelen < QHEADERSZ + sizeof(uint32_t)*3 + sizeof(uint16_t)) { 818 log_msg(LOG_ERR, "msg too short"); 819 return 0; 820 } 821 822 region = region_create(xalloc, free); 823 if(!region) { 824 log_msg(LOG_ERR, "out of memory"); 825 return 0; 826 } 827 828 if(!diff_read_str(in, file_zone_name, sizeof(file_zone_name)) || 829 !diff_read_32(in, &file_serial) || 830 !diff_read_16(in, &file_id) || 831 !diff_read_32(in, &file_seq_nr)) 832 { 833 log_msg(LOG_ERR, "could not part data"); 834 region_destroy(region); 835 return 0; 836 } 837 838 if(strcmp(file_zone_name, zone) != 0 || serialno != file_serial || 839 id != file_id || seq_nr != file_seq_nr) { 840 log_msg(LOG_ERR, "internal error: reading part with changed id"); 841 region_destroy(region); 842 return 0; 843 } 844 msglen = filelen - sizeof(uint32_t)*3 - sizeof(uint16_t) 845 - strlen(file_zone_name); 846 packet = buffer_create(region, QIOBUFSZ); 847 dname_zone = dname_parse(region, zone); 848 zone_db = find_zone(db, dname_zone, opt, child_count); 849 if(!zone_db) { 850 log_msg(LOG_ERR, "no zone exists"); 851 region_destroy(region); 852 /* break out and stop the IXFR, ignore it */ 853 return 2; 854 } 855 856 if(msglen > QIOBUFSZ) { 857 log_msg(LOG_ERR, "msg too long"); 858 region_destroy(region); 859 return 0; 860 } 861 buffer_clear(packet); 862 if(fread(buffer_begin(packet), msglen, 1, in) != 1) { 863 log_msg(LOG_ERR, "short fread: %s", strerror(errno)); 864 region_destroy(region); 865 return 0; 866 } 867 buffer_set_limit(packet, msglen); 868 869 /* only answer section is really used, question, additional and 870 authority section RRs are skipped */ 871 qcount = QDCOUNT(packet); 872 ancount = ANCOUNT(packet); 873 buffer_skip(packet, QHEADERSZ); 874 875 /* skip queries */ 876 for(i=0; i<qcount; ++i) 877 if(!packet_skip_rr(packet, 1)) { 878 log_msg(LOG_ERR, "bad RR in question section"); 879 region_destroy(region); 880 return 0; 881 } 882 883 DEBUG(DEBUG_XFRD,2, (LOG_INFO, "diff: started packet for zone %s", 884 dname_to_string(dname_zone, 0))); 885 /* first RR: check if SOA and correct zone & serialno */ 886 if(*rr_count == 0) { 887 DEBUG(DEBUG_XFRD,2, (LOG_INFO, "diff: %s parse first RR", 888 dname_to_string(dname_zone, 0))); 889 dname = dname_make_from_packet(region, packet, 1, 1); 890 if(!dname) { 891 log_msg(LOG_ERR, "could not parse dname"); 892 region_destroy(region); 893 return 0; 894 } 895 if(dname_compare(dname_zone, dname) != 0) { 896 log_msg(LOG_ERR, "SOA dname %s not equal to zone", 897 dname_to_string(dname,0)); 898 log_msg(LOG_ERR, "zone dname is %s", 899 dname_to_string(dname_zone,0)); 900 region_destroy(region); 901 return 0; 902 } 903 if(!buffer_available(packet, 10)) { 904 log_msg(LOG_ERR, "bad SOA RR"); 905 region_destroy(region); 906 return 0; 907 } 908 if(buffer_read_u16(packet) != TYPE_SOA || 909 buffer_read_u16(packet) != CLASS_IN) { 910 log_msg(LOG_ERR, "first RR not SOA IN"); 911 region_destroy(region); 912 return 0; 913 } 914 buffer_skip(packet, sizeof(uint32_t)); /* ttl */ 915 if(!buffer_available(packet, buffer_read_u16(packet)) || 916 !packet_skip_dname(packet) /* skip prim_ns */ || 917 !packet_skip_dname(packet) /* skip email */) { 918 log_msg(LOG_ERR, "bad SOA RR"); 919 region_destroy(region); 920 return 0; 921 } 922 if(buffer_read_u32(packet) != serialno) { 923 buffer_skip(packet, -4); 924 log_msg(LOG_ERR, "SOA serial %d different from commit %d", 925 buffer_read_u32(packet), serialno); 926 region_destroy(region); 927 return 0; 928 } 929 buffer_skip(packet, sizeof(uint32_t)*4); 930 counter = 1; 931 *rr_count = 1; 932 *is_axfr = 0; 933 *delete_mode = 0; 934 935 DEBUG(DEBUG_XFRD,2, (LOG_INFO, "diff: %s start count %d, ax %d, delmode %d", 936 dname_to_string(dname_zone, 0), *rr_count, *is_axfr, *delete_mode)); 937 } 938 else counter = 0; 939 940 last_in_list = zone_db->apex; 941 for(; counter < ancount; ++counter,++(*rr_count)) 942 { 943 uint16_t type, klass; 944 uint32_t ttl; 945 946 if(!(dname=dname_make_from_packet(region, packet, 1,1))) { 947 log_msg(LOG_ERR, "bad xfr RR dname %d", *rr_count); 948 region_destroy(region); 949 return 0; 950 } 951 if(!buffer_available(packet, 10)) { 952 log_msg(LOG_ERR, "bad xfr RR format %d", *rr_count); 953 region_destroy(region); 954 return 0; 955 } 956 type = buffer_read_u16(packet); 957 klass = buffer_read_u16(packet); 958 ttl = buffer_read_u32(packet); 959 rrlen = buffer_read_u16(packet); 960 if(!buffer_available(packet, rrlen)) { 961 log_msg(LOG_ERR, "bad xfr RR rdata %d, len %d have %d", 962 *rr_count, rrlen, (int)buffer_remaining(packet)); 963 region_destroy(region); 964 return 0; 965 } 966 DEBUG(DEBUG_XFRD,2, (LOG_INFO, "diff: %s parsed count %d, ax %d, delmode %d", 967 dname_to_string(dname_zone, 0), *rr_count, *is_axfr, *delete_mode)); 968 969 if(*rr_count == 1 && type != TYPE_SOA) { 970 /* second RR: if not SOA: this is an AXFR; delete all zone contents */ 971 delete_zone_rrs(db, zone_db); 972 /* add everything else (incl end SOA) */ 973 *delete_mode = 0; 974 *is_axfr = 1; 975 DEBUG(DEBUG_XFRD,2, (LOG_INFO, "diff: %s sawAXFR count %d, ax %d, delmode %d", 976 dname_to_string(dname_zone, 0), *rr_count, *is_axfr, *delete_mode)); 977 } 978 if(*rr_count == 1 && type == TYPE_SOA) { 979 /* if the serial no of the SOA equals the serialno, then AXFR */ 980 size_t bufpos = buffer_position(packet); 981 uint32_t thisserial; 982 if(!packet_skip_dname(packet) || 983 !packet_skip_dname(packet) || 984 buffer_remaining(packet) < sizeof(uint32_t)*5) 985 { 986 log_msg(LOG_ERR, "bad xfr SOA RR formerr."); 987 region_destroy(region); 988 return 0; 989 } 990 thisserial = buffer_read_u32(packet); 991 if(thisserial == serialno) { 992 /* AXFR */ 993 delete_zone_rrs(db, zone_db); 994 *delete_mode = 0; 995 *is_axfr = 1; 996 } 997 /* must have stuff in memory for a successful IXFR, 998 * the serial number of the SOA has been checked 999 * previously (by check_for_bad_serial) if it exists */ 1000 if(!*is_axfr && !domain_find_rrset(zone_db->apex, 1001 zone_db, TYPE_SOA)) { 1002 log_msg(LOG_ERR, "%s SOA serial %d is not " 1003 "in memory, skip IXFR", zone, serialno); 1004 region_destroy(region); 1005 /* break out and stop the IXFR, ignore it */ 1006 return 2; 1007 } 1008 buffer_set_position(packet, bufpos); 1009 } 1010 if(type == TYPE_SOA && !*is_axfr) { 1011 /* switch from delete-part to add-part and back again, 1012 just before soa - so it gets deleted and added too */ 1013 /* this means we switch to delete mode for the final SOA */ 1014 *delete_mode = !*delete_mode; 1015 DEBUG(DEBUG_XFRD,2, (LOG_INFO, "diff: %s IXFRswapdel count %d, ax %d, delmode %d", 1016 dname_to_string(dname_zone, 0), *rr_count, *is_axfr, *delete_mode)); 1017 } 1018 if(type == TYPE_TSIG || type == TYPE_OPT) { 1019 /* ignore pseudo RRs */ 1020 buffer_skip(packet, rrlen); 1021 continue; 1022 } 1023 1024 DEBUG(DEBUG_XFRD,2, (LOG_INFO, "xfr %s RR dname is %s type %s", 1025 *delete_mode?"del":"add", 1026 dname_to_string(dname,0), rrtype_to_string(type))); 1027 if(*delete_mode) { 1028 /* delete this rr */ 1029 if(!*is_axfr && type == TYPE_SOA && counter==ancount-1 1030 && seq_nr == seq_total-1) { 1031 continue; /* do not delete final SOA RR for IXFR */ 1032 } 1033 if(!delete_RR(db, dname, type, klass, last_in_list, packet, 1034 rrlen, zone_db, region, *is_axfr)) { 1035 region_destroy(region); 1036 return 0; 1037 } 1038 if (!*is_axfr && last_in_list->nextdiff) { 1039 last_in_list = last_in_list->nextdiff; 1040 } 1041 } 1042 else 1043 { 1044 /* add this rr */ 1045 if(!add_RR(db, dname, type, klass, ttl, packet, 1046 rrlen, zone_db, *is_axfr)) { 1047 region_destroy(region); 1048 return 0; 1049 } 1050 } 1051 } 1052 fix_empty_terminals(zone_db); 1053 region_destroy(region); 1054 return 1; 1055 } 1056 1057 static int 1058 check_for_bad_serial(namedb_type* db, const char* zone_str, uint32_t old_serial) 1059 { 1060 /* see if serial OK with in-memory serial */ 1061 domain_type* domain; 1062 region_type* region = region_create(xalloc, free); 1063 const dname_type* zone_name = dname_parse(region, zone_str); 1064 zone_type* zone = 0; 1065 domain = domain_table_find(db->domains, zone_name); 1066 if(domain) 1067 zone = domain_find_zone(domain); 1068 if(zone && zone->apex == domain && zone->soa_rrset && old_serial) 1069 { 1070 uint32_t memserial; 1071 memcpy(&memserial, rdata_atom_data(zone->soa_rrset->rrs[0].rdatas[2]), 1072 sizeof(uint32_t)); 1073 if(old_serial != ntohl(memserial)) { 1074 region_destroy(region); 1075 return 1; 1076 } 1077 } 1078 region_destroy(region); 1079 return 0; 1080 } 1081 1082 /* for multiple tcp packets use a data structure that has 1083 * a rbtree (zone_names) with for each zone: 1084 * has a rbtree by sequence number 1085 * with inside a serial_number and ID (for checking only) 1086 * and contains a off_t to the IXFR packet in the file. 1087 * so when you get a commit for a zone, get zone obj, find sequence, 1088 * then check if you have all sequence numbers available. Apply all packets. 1089 */ 1090 struct diff_read_data { 1091 /* rbtree of struct diff_zone*/ 1092 rbtree_t* zones; 1093 /* region for allocation */ 1094 region_type* region; 1095 }; 1096 struct diff_zone { 1097 /* key is dname of zone */ 1098 rbnode_t node; 1099 /* rbtree of struct diff_xfrpart */ 1100 rbtree_t* parts; 1101 }; 1102 struct diff_xfrpart { 1103 /* key is sequence number */ 1104 rbnode_t node; 1105 uint32_t seq_nr; 1106 uint32_t new_serial; 1107 uint16_t id; 1108 off_t file_pos; 1109 }; 1110 1111 static struct diff_read_data* 1112 diff_read_data_create() 1113 { 1114 region_type* region = region_create(xalloc, free); 1115 struct diff_read_data* data = (struct diff_read_data*) 1116 region_alloc(region, sizeof(struct diff_read_data)); 1117 if(!data) { 1118 log_msg(LOG_ERR, "out of memory, %s:%d", __FILE__, __LINE__); 1119 exit(1); 1120 } 1121 data->region = region; 1122 data->zones = rbtree_create(region, 1123 (int (*)(const void *, const void *)) dname_compare); 1124 return data; 1125 } 1126 1127 static struct diff_zone* 1128 diff_read_find_zone(struct diff_read_data* data, const char* name) 1129 { 1130 const dname_type* dname = dname_parse(data->region, name); 1131 struct diff_zone* zp = (struct diff_zone*) 1132 rbtree_search(data->zones, dname); 1133 return zp; 1134 } 1135 1136 static int intcompf(const void* a, const void* b) 1137 { 1138 if(*(uint32_t*)a < *(uint32_t*)b) 1139 return -1; 1140 if(*(uint32_t*)a > *(uint32_t*)b) 1141 return +1; 1142 return 0; 1143 } 1144 1145 static struct diff_zone* 1146 diff_read_insert_zone(struct diff_read_data* data, const char* name) 1147 { 1148 const dname_type* dname = dname_parse(data->region, name); 1149 struct diff_zone* zp = region_alloc(data->region, 1150 sizeof(struct diff_zone)); 1151 if(!zp) { 1152 log_msg(LOG_ERR, "out of memory, %s:%d", __FILE__, __LINE__); 1153 exit(1); 1154 } 1155 zp->node = *RBTREE_NULL; 1156 zp->node.key = dname; 1157 zp->parts = rbtree_create(data->region, intcompf); 1158 rbtree_insert(data->zones, (rbnode_t*)zp); 1159 return zp; 1160 } 1161 1162 static struct diff_xfrpart* 1163 diff_read_find_part(struct diff_zone* zp, uint32_t seq_nr) 1164 { 1165 struct diff_xfrpart* xp = (struct diff_xfrpart*) 1166 rbtree_search(zp->parts, &seq_nr); 1167 return xp; 1168 } 1169 1170 static struct diff_xfrpart* 1171 diff_read_insert_part(struct diff_read_data* data, 1172 struct diff_zone* zp, uint32_t seq_nr) 1173 { 1174 struct diff_xfrpart* xp = region_alloc(data->region, 1175 sizeof(struct diff_xfrpart)); 1176 if(!xp) { 1177 log_msg(LOG_ERR, "out of memory, %s:%d", __FILE__, __LINE__); 1178 exit(1); 1179 } 1180 xp->node = *RBTREE_NULL; 1181 xp->node.key = &xp->seq_nr; 1182 xp->seq_nr = seq_nr; 1183 rbtree_insert(zp->parts, (rbnode_t*)xp); 1184 return xp; 1185 } 1186 1187 /* mark commit as rollback and close inputfile, fatal exits */ 1188 static void 1189 mark_and_exit(nsd_options_t* opt, FILE* f, off_t commitpos, const char* desc) 1190 { 1191 const char* filename = opt->difffile; 1192 fclose(f); 1193 if(!(f = fopen(filename, "r+"))) { 1194 log_msg(LOG_ERR, "mark xfr, failed to re-open difffile %s: %s", 1195 filename, strerror(errno)); 1196 } else if(fseeko(f, commitpos, SEEK_SET) == -1) { 1197 log_msg(LOG_INFO, "could not fseeko: %s.", strerror(errno)); 1198 fclose(f); 1199 } else { 1200 uint8_t c = 0; 1201 (void)write_data(f, &c, sizeof(c)); 1202 fclose(f); 1203 log_msg(LOG_ERR, "marked xfr as failed: %s", desc); 1204 log_msg(LOG_ERR, "marked xfr so that next reload can succeed"); 1205 } 1206 exit(1); 1207 } 1208 1209 static int 1210 read_sure_part(namedb_type* db, FILE *in, nsd_options_t* opt, 1211 struct diff_read_data* data, struct diff_log** log, 1212 size_t child_count) 1213 { 1214 char zone_buf[3072]; 1215 char log_buf[5120]; 1216 uint32_t old_serial, new_serial, num_parts; 1217 uint16_t id; 1218 uint8_t committed; 1219 struct diff_zone *zp; 1220 uint32_t i; 1221 int have_all_parts = 1; 1222 struct diff_log* thislog = 0; 1223 off_t commitpos; 1224 1225 /* read zone name and serial */ 1226 if(!diff_read_str(in, zone_buf, sizeof(zone_buf)) || 1227 !diff_read_32(in, &old_serial) || 1228 !diff_read_32(in, &new_serial) || 1229 !diff_read_16(in, &id) || 1230 !diff_read_32(in, &num_parts)) { 1231 log_msg(LOG_ERR, "diff file bad commit part"); 1232 return 0; 1233 } 1234 commitpos = ftello(in); /* position of commit byte */ 1235 if(commitpos == -1) { 1236 log_msg(LOG_INFO, "could not ftello: %s.", strerror(errno)); 1237 return 0; 1238 } 1239 if(!diff_read_8(in, &committed) || 1240 !diff_read_str(in, log_buf, sizeof(log_buf)) ) 1241 { 1242 log_msg(LOG_ERR, "diff file bad commit part"); 1243 return 0; 1244 } 1245 1246 if(log) { 1247 thislog = (struct diff_log*)region_alloc(db->region, sizeof(struct diff_log)); 1248 if(!thislog) { 1249 log_msg(LOG_ERR, "out of memory, %s:%d", __FILE__, __LINE__); 1250 exit(1); 1251 } 1252 thislog->zone_name = region_strdup(db->region, zone_buf); 1253 thislog->comment = region_strdup(db->region, log_buf); 1254 thislog->error = 0; 1255 thislog->next = *log; 1256 *log = thislog; 1257 } 1258 1259 /* has been read in completely */ 1260 zp = diff_read_find_zone(data, zone_buf); 1261 if(!zp) { 1262 log_msg(LOG_ERR, "diff file commit without IXFR"); 1263 if(thislog) 1264 thislog->error = "error no IXFR parts"; 1265 return 1; 1266 } 1267 if(committed && check_for_bad_serial(db, zone_buf, old_serial)) { 1268 DEBUG(DEBUG_XFRD,1, (LOG_ERR, 1269 "skipping diff file commit with bad serial")); 1270 zp->parts->root = RBTREE_NULL; 1271 zp->parts->count = 0; 1272 if(thislog) 1273 thislog->error = "error bad serial"; 1274 return 1; 1275 } 1276 for(i=0; i<num_parts; i++) { 1277 struct diff_xfrpart *xp = diff_read_find_part(zp, i); 1278 if(!xp || xp->id != id || xp->new_serial != new_serial) { 1279 have_all_parts = 0; 1280 } 1281 } 1282 if(!have_all_parts) { 1283 DEBUG(DEBUG_XFRD,1, (LOG_ERR, 1284 "skipping diff file commit without all parts")); 1285 if(thislog) 1286 thislog->error = "error missing parts"; 1287 } 1288 1289 if(committed && have_all_parts) 1290 { 1291 int is_axfr=0, delete_mode=0, rr_count=0; 1292 off_t resume_pos; 1293 1294 DEBUG(DEBUG_XFRD,1, (LOG_INFO, "processing xfr: %s", log_buf)); 1295 1296 #ifdef NSEC3 1297 #ifndef FULL_PREHASH 1298 struct region *region; 1299 dname_type const *zone_dname; 1300 struct zone *zone; 1301 1302 region = region_create(xalloc, free); 1303 if (region == NULL) { 1304 log_msg(LOG_ERR, "out of memory"); 1305 return 0; 1306 } 1307 zone_dname = dname_parse(region, zone_buf); 1308 if (zone_dname == NULL) { 1309 log_msg(LOG_ERR, "out of memory"); 1310 region_destroy(region); 1311 return 0; 1312 } 1313 zone = find_zone(db, zone_dname, opt, child_count); 1314 region_destroy(region); 1315 if (zone == NULL) { 1316 log_msg(LOG_ERR, "no zone exists"); 1317 /* just stop trying applying ixfr */ 1318 return 1; 1319 } 1320 if (0 != namedb_nsec3_mod_domains_create(db)) { 1321 log_msg(LOG_ERR, 1322 "unable to allocate space " 1323 "for modified NSEC3 domains"); 1324 return 0; 1325 } 1326 #endif /* !FULL_PREHASH */ 1327 #endif /* NSEC3 */ 1328 1329 resume_pos = ftello(in); 1330 if(resume_pos == -1) { 1331 log_msg(LOG_INFO, "could not ftello: %s.", strerror(errno)); 1332 return 0; 1333 } 1334 for(i=0; i<num_parts; i++) { 1335 struct diff_xfrpart *xp = diff_read_find_part(zp, i); 1336 int ret; 1337 DEBUG(DEBUG_XFRD,2, (LOG_INFO, "processing xfr: apply part %d", (int)i)); 1338 ret = apply_ixfr(db, in, &xp->file_pos, zone_buf, new_serial, opt, 1339 id, xp->seq_nr, num_parts, &is_axfr, &delete_mode, 1340 &rr_count, child_count); 1341 if(ret == 0) { 1342 log_msg(LOG_ERR, "bad ixfr packet part %d in %s", (int)i, 1343 opt->difffile); 1344 mark_and_exit(opt, in, commitpos, log_buf); 1345 } else if(ret == 2) { 1346 break; 1347 } 1348 } 1349 #ifdef NSEC3 1350 #ifndef FULL_PREHASH 1351 if (is_axfr != 0) 1352 prehash_zone(db, zone); 1353 else 1354 prehash_zone_incremental(db, zone); 1355 #endif /* !FULL_PREHASH */ 1356 #endif /* NSEC3 */ 1357 1358 if(fseeko(in, resume_pos, SEEK_SET) == -1) { 1359 log_msg(LOG_INFO, "could not fseeko: %s.", strerror(errno)); 1360 return 0; 1361 } 1362 } 1363 else { 1364 DEBUG(DEBUG_XFRD,1, (LOG_INFO, "skipping xfr: %s", log_buf)); 1365 } 1366 1367 /* clean out the parts for the zone after the commit/rollback */ 1368 zp->parts->root = RBTREE_NULL; 1369 zp->parts->count = 0; 1370 return 1; 1371 } 1372 1373 static int 1374 store_ixfr_data(FILE *in, uint32_t len, struct diff_read_data* data, off_t* startpos) 1375 { 1376 char zone_name[3072]; 1377 struct diff_zone* zp; 1378 struct diff_xfrpart* xp; 1379 uint32_t new_serial, seq; 1380 uint16_t id; 1381 if(!diff_read_str(in, zone_name, sizeof(zone_name)) || 1382 !diff_read_32(in, &new_serial) || 1383 !diff_read_16(in, &id) || 1384 !diff_read_32(in, &seq)) { 1385 log_msg(LOG_INFO, "could not read ixfr store info: file format error"); 1386 return 0; 1387 } 1388 len -= sizeof(uint32_t)*3 + sizeof(uint16_t) + strlen(zone_name); 1389 if(fseeko(in, len, SEEK_CUR) == -1) 1390 log_msg(LOG_INFO, "fseek failed: %s", strerror(errno)); 1391 /* store the info */ 1392 zp = diff_read_find_zone(data, zone_name); 1393 if(!zp) 1394 zp = diff_read_insert_zone(data, zone_name); 1395 xp = diff_read_find_part(zp, seq); 1396 if(xp) { 1397 log_msg(LOG_INFO, "discarding partial xfr part: %s %d", zone_name, seq); 1398 /* overwrite with newer value (which probably relates to next commit) */ 1399 } 1400 else { 1401 xp = diff_read_insert_part(data, zp, seq); 1402 } 1403 xp->new_serial = new_serial; 1404 xp->id = id; 1405 memmove(&xp->file_pos, startpos, sizeof(off_t)); 1406 return 1; 1407 } 1408 1409 static int 1410 read_process_part(namedb_type* db, FILE *in, uint32_t type, 1411 nsd_options_t* opt, struct diff_read_data* data, 1412 struct diff_log** log, size_t child_count, off_t* startpos) 1413 { 1414 uint32_t len, len2; 1415 1416 /* read length */ 1417 if(!diff_read_32(in, &len)) 1418 return 1; 1419 /* read content */ 1420 if(type == DIFF_PART_IXFR) { 1421 DEBUG(DEBUG_XFRD,2, (LOG_INFO, "part IXFR len %d", len)); 1422 if(!store_ixfr_data(in, len, data, startpos)) 1423 return 0; 1424 } 1425 else if(type == DIFF_PART_SURE) { 1426 DEBUG(DEBUG_XFRD,2, (LOG_INFO, "part SURE len %d", len)); 1427 if(!read_sure_part(db, in, opt, data, log, child_count)) 1428 return 0; 1429 } else { 1430 DEBUG(DEBUG_XFRD,1, (LOG_INFO, "unknown part %x len %d", type, len)); 1431 return 0; 1432 } 1433 /* read length */ 1434 if(!diff_read_32(in, &len2)) 1435 return 1; /* short read is OK */ 1436 /* verify length */ 1437 if(len != len2) 1438 return 0; /* bad data is wrong */ 1439 return 1; 1440 } 1441 1442 /* 1443 * Finds smallest offset in data structs 1444 * returns 0 if no offsets in the data structs. 1445 */ 1446 static int 1447 find_smallest_offset(struct diff_read_data* data, off_t* offset) 1448 { 1449 int found_any = 0; 1450 struct diff_zone* dz; 1451 struct diff_xfrpart* dx; 1452 off_t mem_offset, mem_fpos; 1453 1454 if(!data || !data->zones) 1455 return 0; 1456 RBTREE_FOR(dz, struct diff_zone*, data->zones) 1457 { 1458 if(!dz->parts) 1459 continue; 1460 RBTREE_FOR(dx, struct diff_xfrpart*, dz->parts) 1461 { 1462 memmove(&mem_fpos, &dx->file_pos, sizeof(off_t)); 1463 1464 if(found_any) { 1465 memmove(&mem_offset, offset, sizeof(off_t)); 1466 1467 if(mem_fpos < mem_offset) 1468 memmove(offset, &mem_fpos, sizeof(off_t)); 1469 } else { 1470 found_any = 1; 1471 memmove(offset, &mem_fpos, sizeof(off_t)); 1472 } 1473 } 1474 } 1475 1476 return found_any; 1477 } 1478 1479 int 1480 diff_read_file(namedb_type* db, nsd_options_t* opt, struct diff_log** log, 1481 size_t child_count) 1482 { 1483 const char* filename = opt->difffile; 1484 FILE *df; 1485 uint32_t type, timestamp[2], curr_timestamp[2]; 1486 struct diff_read_data* data = diff_read_data_create(); 1487 off_t startpos; 1488 1489 df = fopen(filename, "r"); 1490 if(!df) { 1491 DEBUG(DEBUG_XFRD,1, (LOG_INFO, "could not open file %s for reading: %s", 1492 filename, strerror(errno))); 1493 region_destroy(data->region); 1494 return 1; 1495 } 1496 1497 /* check timestamp */ 1498 curr_timestamp[0] = (uint32_t) db->diff_timestamp.tv_sec; 1499 curr_timestamp[1] = (uint32_t) db->diff_timestamp.tv_usec; 1500 1501 if(!diff_read_32(df, &type)) { 1502 DEBUG(DEBUG_XFRD,1, (LOG_INFO, "difffile %s is empty", 1503 filename)); 1504 db->diff_skip = 0; 1505 db->diff_pos = 0; 1506 } 1507 else if (!diff_read_32(df, ×tamp[0]) || 1508 !diff_read_32(df, ×tamp[1])) { 1509 log_msg(LOG_ERR, "difffile %s bad first part: no timestamp", 1510 filename); 1511 region_destroy(data->region); 1512 return 0; 1513 } 1514 else if (curr_timestamp[0] != timestamp[0] || 1515 curr_timestamp[1] != timestamp[1]) { 1516 /* new timestamp, no skipping */ 1517 db->diff_timestamp.tv_sec = (time_t) timestamp[0]; 1518 db->diff_timestamp.tv_usec = (suseconds_t) timestamp[1]; 1519 1520 if (db->diff_skip) { 1521 DEBUG(DEBUG_XFRD,1, (LOG_INFO, "new timestamp on " 1522 "difffile %s, restoring diff_skip and diff_pos " 1523 "[old timestamp: %u.%u; new timestamp: %u.%u]", 1524 filename, curr_timestamp[0], curr_timestamp[1], 1525 timestamp[0], timestamp[1])); 1526 db->diff_skip = 0; 1527 db->diff_pos = 0; 1528 } 1529 } 1530 1531 /* Always seek, to diff_pos or to beginning of the file. */ 1532 if (fseeko(df, 0, SEEK_SET)==-1) { 1533 log_msg(LOG_INFO, "could not fseeko file %s: %s.", filename, 1534 strerror(errno)); 1535 region_destroy(data->region); 1536 return 0; 1537 } 1538 if(db->diff_skip) { 1539 DEBUG(DEBUG_XFRD,1, (LOG_INFO, "skip diff file")); 1540 if(fseeko(df, db->diff_pos, SEEK_SET)==-1) { 1541 log_msg(LOG_INFO, "could not fseeko file %s: %s. " 1542 "Reread from start.", filename, 1543 strerror(errno)); 1544 } 1545 } 1546 1547 startpos = ftello(df); 1548 if(startpos == -1) { 1549 log_msg(LOG_INFO, "could not ftello: %s.", strerror(errno)); 1550 region_destroy(data->region); 1551 return 0; 1552 } 1553 1554 DEBUG(DEBUG_XFRD,1, (LOG_INFO, "start of diff file read at pos %u", 1555 (uint32_t) db->diff_pos)); 1556 while(diff_read_32(df, &type)) 1557 { 1558 DEBUG(DEBUG_XFRD,2, (LOG_INFO, "iter loop")); 1559 1560 /* read timestamp */ 1561 if(!diff_read_32(df, ×tamp[0]) || 1562 !diff_read_32(df, ×tamp[1])) { 1563 log_msg(LOG_INFO, "could not read timestamp: %s.", 1564 strerror(errno)); 1565 region_destroy(data->region); 1566 return 0; 1567 } 1568 1569 if(!read_process_part(db, df, type, opt, data, log, 1570 child_count, &startpos)) 1571 { 1572 log_msg(LOG_INFO, "error processing diff file"); 1573 region_destroy(data->region); 1574 return 0; 1575 } 1576 startpos = ftello(df); 1577 if(startpos == -1) { 1578 log_msg(LOG_INFO, "could not ftello: %s.", strerror(errno)); 1579 region_destroy(data->region); 1580 return 0; 1581 } 1582 } 1583 DEBUG(DEBUG_XFRD,1, (LOG_INFO, "end of diff file read")); 1584 1585 if(find_smallest_offset(data, &db->diff_pos)) { 1586 /* can skip to the first unused element */ 1587 DEBUG(DEBUG_XFRD,2, (LOG_INFO, "next time skip diff file")); 1588 db->diff_skip = 1; 1589 } else { 1590 /* all processed, can skip to here next time */ 1591 DEBUG(DEBUG_XFRD,2, (LOG_INFO, "next time skip diff file")); 1592 db->diff_skip = 1; 1593 db->diff_pos = ftello(df); 1594 if(db->diff_pos == -1) { 1595 log_msg(LOG_INFO, "could not ftello: %s.", 1596 strerror(errno)); 1597 db->diff_skip = 0; 1598 } 1599 } 1600 1601 region_destroy(data->region); 1602 fclose(df); 1603 return 1; 1604 } 1605 1606 static int diff_broken(FILE *df, off_t* break_pos) 1607 { 1608 uint32_t type, len, len2; 1609 *break_pos = ftello(df); 1610 1611 /* try to read and validate parts of the file */ 1612 while(diff_read_32(df, &type)) /* cannot read type is no error, normal EOF */ 1613 { 1614 /* check type */ 1615 if(type != DIFF_PART_IXFR && type != DIFF_PART_SURE) 1616 return 1; 1617 /* check length */ 1618 if(!diff_read_32(df, &len)) 1619 return 1; /* EOF inside the part is error */ 1620 if(fseeko(df, len, SEEK_CUR) == -1) 1621 { 1622 log_msg(LOG_INFO, "fseeko failed: %s", strerror(errno)); 1623 return 1; 1624 } 1625 /* fseek clears EOF flag, but try reading length value, 1626 if EOF, the part is truncated */ 1627 if(!diff_read_32(df, &len2)) 1628 return 1; 1629 if(len != len2) 1630 return 1; /* bad part, lengths must agree */ 1631 /* this part is ok */ 1632 *break_pos = ftello(df); 1633 } 1634 return 0; 1635 } 1636 1637 void diff_snip_garbage(namedb_type* db, nsd_options_t* opt) 1638 { 1639 off_t break_pos; 1640 const char* filename = opt->difffile; 1641 FILE *df; 1642 1643 /* open file here and keep open, so it cannot change under our nose */ 1644 df = fopen(filename, "r+"); 1645 if(!df) { 1646 DEBUG(DEBUG_XFRD,1, (LOG_INFO, "could not open file %s for garbage collecting: %s", 1647 filename, strerror(errno))); 1648 return; 1649 } 1650 /* and skip into file, since nsd does not read anything before the pos */ 1651 if(db->diff_skip) { 1652 DEBUG(DEBUG_XFRD,1, (LOG_INFO, "garbage collect skip diff file")); 1653 if(fseeko(df, db->diff_pos, SEEK_SET)==-1) { 1654 log_msg(LOG_INFO, "could not fseeko file %s: %s.", 1655 filename, strerror(errno)); 1656 fclose(df); 1657 return; 1658 } 1659 } 1660 1661 /* detect break point */ 1662 if(diff_broken(df, &break_pos)) 1663 { 1664 /* snip off at break_pos */ 1665 DEBUG(DEBUG_XFRD,1, (LOG_INFO, "snipping off trailing partial part of %s", 1666 filename)); 1667 if(ftruncate(fileno(df), break_pos) == -1) 1668 log_msg(LOG_ERR, "ftruncate %s failed: %s", 1669 filename, strerror(errno)); 1670 } 1671 1672 fclose(df); 1673 } 1674