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