1/* 2 * ixfrcreate.c -- generating IXFR differences from zone files. 3 * 4 * Copyright (c) 2021, NLnet Labs. All rights reserved. 5 * 6 * See LICENSE for the license. 7 * 8 */ 9 10#include "config.h" 11#include <stdio.h> 12#include <errno.h> 13#include <unistd.h> 14#include "ixfrcreate.h" 15#include "namedb.h" 16#include "ixfr.h" 17#include "options.h" 18 19/* spool a uint16_t to file */ 20static int spool_u16(FILE* out, uint16_t val) 21{ 22 if(!fwrite(&val, sizeof(val), 1, out)) { 23 return 0; 24 } 25 return 1; 26} 27 28/* spool a uint32_t to file */ 29static int spool_u32(FILE* out, uint32_t val) 30{ 31 if(!fwrite(&val, sizeof(val), 1, out)) { 32 return 0; 33 } 34 return 1; 35} 36 37/* spool dname to file */ 38static int spool_dname(FILE* out, dname_type* dname) 39{ 40 uint16_t namelen = dname->name_size; 41 if(!fwrite(&namelen, sizeof(namelen), 1, out)) { 42 return 0; 43 } 44 if(!fwrite(dname_name(dname), namelen, 1, out)) { 45 return 0; 46 } 47 return 1; 48} 49 50/* calculate the rdatalen of an RR */ 51static size_t rr_rdatalen_uncompressed(rr_type* rr) 52{ 53 int i; 54 size_t rdlen_uncompressed = 0; 55 for(i=0; i<rr->rdata_count; i++) { 56 if(rdata_atom_is_domain(rr->type, i)) { 57 rdlen_uncompressed += domain_dname(rr->rdatas[i].domain) 58 ->name_size; 59 } else { 60 rdlen_uncompressed += rr->rdatas[i].data[0]; 61 } 62 } 63 return rdlen_uncompressed; 64} 65 66/* spool the data for one rr into the file */ 67static int spool_rr_data(FILE* out, rr_type* rr) 68{ 69 int i; 70 uint16_t rdlen; 71 if(!spool_u32(out, rr->ttl)) 72 return 0; 73 rdlen = rr_rdatalen_uncompressed(rr); 74 if(!spool_u16(out, rdlen)) 75 return 0; 76 for(i=0; i<rr->rdata_count; i++) { 77 if(rdata_atom_is_domain(rr->type, i)) { 78 if(!fwrite(dname_name(domain_dname( 79 rr->rdatas[i].domain)), domain_dname( 80 rr->rdatas[i].domain)->name_size, 1, out)) 81 return 0; 82 } else { 83 if(!fwrite(&rr->rdatas[i].data[1], 84 rr->rdatas[i].data[0], 1, out)) 85 return 0; 86 } 87 } 88 return 1; 89} 90 91/* spool one rrset to file */ 92static int spool_rrset(FILE* out, rrset_type* rrset) 93{ 94 int i; 95 if(rrset->rr_count == 0) 96 return 1; 97 if(!spool_u16(out, rrset->rrs[0].type)) 98 return 0; 99 if(!spool_u16(out, rrset->rrs[0].klass)) 100 return 0; 101 if(!spool_u16(out, rrset->rr_count)) 102 return 0; 103 for(i=0; i<rrset->rr_count; i++) { 104 if(!spool_rr_data(out, &rrset->rrs[i])) 105 return 0; 106 } 107 return 1; 108} 109 110/* spool rrsets to file */ 111static int spool_rrsets(FILE* out, rrset_type* rrsets, struct zone* zone) 112{ 113 rrset_type* s; 114 for(s=rrsets; s; s=s->next) { 115 if(s->zone != zone) 116 continue; 117 if(!spool_rrset(out, s)) { 118 return 0; 119 } 120 } 121 return 1; 122} 123 124/* count number of rrsets for a domain */ 125static size_t domain_count_rrsets(domain_type* domain, zone_type* zone) 126{ 127 rrset_type* s; 128 size_t count = 0; 129 for(s=domain->rrsets; s; s=s->next) { 130 if(s->zone == zone) 131 count++; 132 } 133 return count; 134} 135 136/* spool the domain names to file, each one in turn. end with enddelimiter */ 137static int spool_domains(FILE* out, struct zone* zone) 138{ 139 domain_type* domain; 140 for(domain = zone->apex; domain && domain_is_subdomain(domain, 141 zone->apex); domain = domain_next(domain)) { 142 uint32_t count = domain_count_rrsets(domain, zone); 143 if(count == 0) 144 continue; 145 /* write the name */ 146 if(!spool_dname(out, domain_dname(domain))) 147 return 0; 148 if(!spool_u32(out, count)) 149 return 0; 150 /* write the rrsets */ 151 if(!spool_rrsets(out, domain->rrsets, zone)) 152 return 0; 153 } 154 /* the end delimiter is a 0 length. domain names are not zero length */ 155 if(!spool_u16(out, 0)) 156 return 0; 157 return 1; 158} 159 160/* spool the namedb zone to the file. print error on failure. */ 161static int spool_zone_to_file(struct zone* zone, char* file_name, 162 uint32_t serial) 163{ 164 FILE* out; 165 out = fopen(file_name, "w"); 166 if(!out) { 167 log_msg(LOG_ERR, "could not open %s for writing: %s", 168 file_name, strerror(errno)); 169 return 0; 170 } 171 if(!spool_dname(out, domain_dname(zone->apex))) { 172 log_msg(LOG_ERR, "could not write %s: %s", 173 file_name, strerror(errno)); 174 fclose(out); 175 return 0; 176 } 177 if(!spool_u32(out, serial)) { 178 log_msg(LOG_ERR, "could not write %s: %s", 179 file_name, strerror(errno)); 180 fclose(out); 181 return 0; 182 } 183 if(!spool_domains(out, zone)) { 184 log_msg(LOG_ERR, "could not write %s: %s", 185 file_name, strerror(errno)); 186 fclose(out); 187 return 0; 188 } 189 fclose(out); 190 return 1; 191} 192 193/* create ixfr spool file name */ 194static int create_ixfr_spool_name(struct ixfr_create* ixfrcr, 195 const char* zfile) 196{ 197 char buf[1024]; 198 snprintf(buf, sizeof(buf), "%s.spoolzone.%u", zfile, 199 (unsigned)getpid()); 200 ixfrcr->file_name = strdup(buf); 201 if(!ixfrcr->file_name) 202 return 0; 203 return 1; 204} 205 206/* start ixfr creation */ 207struct ixfr_create* ixfr_create_start(struct zone* zone, const char* zfile, 208 uint64_t ixfr_size, int errorcmdline) 209{ 210 struct ixfr_create* ixfrcr = (struct ixfr_create*)calloc(1, 211 sizeof(*ixfrcr)); 212 if(!ixfrcr) { 213 log_msg(LOG_ERR, "malloc failure"); 214 return NULL; 215 } 216 ixfrcr->zone_name_len = domain_dname(zone->apex)->name_size; 217 ixfrcr->zone_name = (uint8_t*)malloc(ixfrcr->zone_name_len); 218 if(!ixfrcr->zone_name) { 219 free(ixfrcr); 220 log_msg(LOG_ERR, "malloc failure"); 221 return NULL; 222 } 223 memmove(ixfrcr->zone_name, dname_name(domain_dname(zone->apex)), 224 ixfrcr->zone_name_len); 225 226 if(!create_ixfr_spool_name(ixfrcr, zfile)) { 227 ixfr_create_free(ixfrcr); 228 log_msg(LOG_ERR, "malloc failure"); 229 return NULL; 230 } 231 ixfrcr->old_serial = zone_get_current_serial(zone); 232 if(!spool_zone_to_file(zone, ixfrcr->file_name, ixfrcr->old_serial)) { 233 ixfr_create_free(ixfrcr); 234 return NULL; 235 } 236 if(zone->opts && zone->opts->pattern) 237 ixfrcr->max_size = (size_t)zone->opts->pattern->ixfr_size; 238 else ixfrcr->max_size = (size_t)ixfr_size; 239 ixfrcr->errorcmdline = errorcmdline; 240 return ixfrcr; 241} 242 243/* free ixfr create */ 244void ixfr_create_free(struct ixfr_create* ixfrcr) 245{ 246 if(!ixfrcr) 247 return; 248 free(ixfrcr->file_name); 249 free(ixfrcr->zone_name); 250 free(ixfrcr); 251} 252 253/* read uint16_t from spool */ 254static int read_spool_u16(FILE* spool, uint16_t* val) 255{ 256 if(fread(val, sizeof(*val), 1, spool) < 1) 257 return 0; 258 return 1; 259} 260 261/* read uint32_t from spool */ 262static int read_spool_u32(FILE* spool, uint32_t* val) 263{ 264 if(fread(val, sizeof(*val), 1, spool) < 1) 265 return 0; 266 return 1; 267} 268 269/* read dname from spool */ 270static int read_spool_dname(FILE* spool, uint8_t* buf, size_t buflen, 271 size_t* dname_len) 272{ 273 uint16_t len; 274 if(fread(&len, sizeof(len), 1, spool) < 1) 275 return 0; 276 if(len > buflen) { 277 log_msg(LOG_ERR, "dname too long"); 278 return 0; 279 } 280 if(len > 0) { 281 if(fread(buf, len, 1, spool) < 1) 282 return 0; 283 } 284 *dname_len = len; 285 return 1; 286} 287 288/* read and check the spool file header */ 289static int read_spool_header(FILE* spool, struct ixfr_create* ixfrcr) 290{ 291 uint8_t dname[MAXDOMAINLEN+1]; 292 size_t dname_len; 293 uint32_t serial; 294 /* read apex */ 295 if(!read_spool_dname(spool, dname, sizeof(dname), &dname_len)) { 296 log_msg(LOG_ERR, "error reading file %s: %s", 297 ixfrcr->file_name, strerror(errno)); 298 return 0; 299 } 300 /* read serial */ 301 if(!read_spool_u32(spool, &serial)) { 302 log_msg(LOG_ERR, "error reading file %s: %s", 303 ixfrcr->file_name, strerror(errno)); 304 return 0; 305 } 306 307 /* check */ 308 if(ixfrcr->zone_name_len != dname_len || 309 memcmp(ixfrcr->zone_name, dname, ixfrcr->zone_name_len) != 0) { 310 log_msg(LOG_ERR, "error file %s does not contain the correct zone apex", 311 ixfrcr->file_name); 312 return 0; 313 } 314 if(ixfrcr->old_serial != serial) { 315 log_msg(LOG_ERR, "error file %s does not contain the correct zone serial", 316 ixfrcr->file_name); 317 return 0; 318 } 319 return 1; 320} 321 322/* store the old soa record when we encounter it on the spool */ 323static int process_store_oldsoa(struct ixfr_store* store, uint8_t* dname, 324 size_t dname_len, uint16_t tp, uint16_t kl, uint32_t ttl, uint8_t* buf, 325 uint16_t rdlen) 326{ 327 if(store->data->oldsoa) { 328 log_msg(LOG_ERR, "error spool contains multiple SOA records"); 329 return 0; 330 } 331 if(!ixfr_store_oldsoa_uncompressed(store, dname, dname_len, tp, kl, 332 ttl, buf, rdlen)) { 333 log_msg(LOG_ERR, "out of memory"); 334 return 0; 335 } 336 return 1; 337} 338 339/* see if rdata matches, true if equal */ 340static int rdata_match(struct rr* rr, uint8_t* rdata, uint16_t rdlen) 341{ 342 size_t rdpos = 0; 343 int i; 344 for(i=0; i<rr->rdata_count; i++) { 345 if(rdata_atom_is_domain(rr->type, i)) { 346 if(rdpos + domain_dname(rr->rdatas[i].domain)->name_size 347 > rdlen) 348 return 0; 349 if(memcmp(rdata+rdpos, 350 dname_name(domain_dname(rr->rdatas[i].domain)), 351 domain_dname(rr->rdatas[i].domain)->name_size) 352 != 0) 353 return 0; 354 rdpos += domain_dname(rr->rdatas[i].domain)->name_size; 355 } else { 356 if(rdpos + rr->rdatas[i].data[0] > rdlen) 357 return 0; 358 if(memcmp(rdata+rdpos, &rr->rdatas[i].data[1], 359 rr->rdatas[i].data[0]) != 0) 360 return 0; 361 rdpos += rr->rdatas[i].data[0]; 362 } 363 } 364 if(rdpos != rdlen) 365 return 0; 366 return 1; 367} 368 369/* find an rdata in an rrset, true if found and sets index found */ 370static int rrset_find_rdata(struct rrset* rrset, uint32_t ttl, uint8_t* rdata, 371 uint16_t rdlen, uint16_t* index) 372{ 373 int i; 374 for(i=0; i<rrset->rr_count; i++) { 375 if(rrset->rrs[i].ttl != ttl) 376 continue; 377 if(rdata_match(&rrset->rrs[i], rdata, rdlen)) { 378 *index = i; 379 return 1; 380 } 381 } 382 return 0; 383} 384 385/* sort comparison for uint16 elements */ 386static int sort_uint16(const void* x, const void* y) 387{ 388 const uint16_t* ax = (const uint16_t*)x; 389 const uint16_t* ay = (const uint16_t*)y; 390 if(*ax < *ay) 391 return -1; 392 if(*ax > *ay) 393 return 1; 394 return 0; 395} 396 397/* spool read an rrset, it is a deleted RRset */ 398static int process_diff_rrset(FILE* spool, struct ixfr_create* ixfrcr, 399 struct ixfr_store* store, struct domain* domain, 400 uint16_t tp, uint16_t kl, uint16_t rrcount, struct rrset* rrset) 401{ 402 /* read RRs from file and see if they are added, deleted or in both */ 403 uint8_t buf[MAX_RDLENGTH]; 404 uint16_t marked[65536]; 405 size_t marked_num = 0, atmarked; 406 int i; 407 for(i=0; i<rrcount; i++) { 408 uint16_t rdlen, index; 409 uint32_t ttl; 410 if(!read_spool_u32(spool, &ttl) || 411 !read_spool_u16(spool, &rdlen)) { 412 log_msg(LOG_ERR, "error reading file %s: %s", 413 ixfrcr->file_name, strerror(errno)); 414 return 0; 415 } 416 /* because rdlen is uint16_t always smaller than sizeof(buf)*/ 417#pragma GCC diagnostic push 418#pragma GCC diagnostic ignored "-Wtype-limits" 419 assert(rdlen <= sizeof(buf)); 420#pragma GCC diagnostic pop 421 if(fread(buf, rdlen, 1, spool) < 1) { 422 log_msg(LOG_ERR, "error reading file %s: %s", 423 ixfrcr->file_name, strerror(errno)); 424 return 0; 425 } 426 if(tp == TYPE_SOA) { 427 if(!process_store_oldsoa(store, 428 (void*)dname_name(domain_dname(domain)), 429 domain_dname(domain)->name_size, tp, kl, ttl, 430 buf, rdlen)) 431 return 0; 432 } 433 /* see if the rr is in the RRset */ 434 if(rrset_find_rdata(rrset, ttl, buf, rdlen, &index)) { 435 /* it is in both, mark it */ 436 marked[marked_num++] = index; 437 } else { 438 /* not in new rrset, but only on spool, it is 439 * a deleted RR */ 440 if(!ixfr_store_delrr_uncompressed(store, 441 (void*)dname_name(domain_dname(domain)), 442 domain_dname(domain)->name_size, 443 tp, kl, ttl, buf, rdlen)) { 444 log_msg(LOG_ERR, "out of memory"); 445 return 0; 446 } 447 } 448 } 449 /* now that we are done, see if RRs in the rrset are not marked, 450 * and thus are new rrs that are added */ 451 qsort(marked, marked_num, sizeof(marked[0]), &sort_uint16); 452 atmarked = 0; 453 for(i=0; i<rrset->rr_count; i++) { 454 if(atmarked < marked_num && marked[atmarked] == i) { 455 /* the item is in the marked list, skip it */ 456 atmarked++; 457 continue; 458 } 459 /* not in the marked list, the RR is added */ 460 if(!ixfr_store_addrr_rdatas(store, domain_dname(domain), 461 rrset->rrs[i].type, rrset->rrs[i].klass, 462 rrset->rrs[i].ttl, rrset->rrs[i].rdatas, 463 rrset->rrs[i].rdata_count)) { 464 log_msg(LOG_ERR, "out of memory"); 465 return 0; 466 } 467 } 468 return 1; 469} 470 471/* spool read an rrset, it is a deleted RRset */ 472static int process_spool_delrrset(FILE* spool, struct ixfr_create* ixfrcr, 473 struct ixfr_store* store, uint8_t* dname, size_t dname_len, 474 uint16_t tp, uint16_t kl, uint16_t rrcount) 475{ 476 /* read the RRs from file and add to del list. */ 477 uint8_t buf[MAX_RDLENGTH]; 478 int i; 479 for(i=0; i<rrcount; i++) { 480 uint16_t rdlen; 481 uint32_t ttl; 482 if(!read_spool_u32(spool, &ttl) || 483 !read_spool_u16(spool, &rdlen)) { 484 log_msg(LOG_ERR, "error reading file %s: %s", 485 ixfrcr->file_name, strerror(errno)); 486 return 0; 487 } 488 /* because rdlen is uint16_t always smaller than sizeof(buf)*/ 489#pragma GCC diagnostic push 490#pragma GCC diagnostic ignored "-Wtype-limits" 491 assert(rdlen <= sizeof(buf)); 492#pragma GCC diagnostic pop 493 if(fread(buf, rdlen, 1, spool) < 1) { 494 log_msg(LOG_ERR, "error reading file %s: %s", 495 ixfrcr->file_name, strerror(errno)); 496 return 0; 497 } 498 if(tp == TYPE_SOA) { 499 if(!process_store_oldsoa(store, dname, dname_len, 500 tp, kl, ttl, buf, rdlen)) 501 return 0; 502 } 503 if(!ixfr_store_delrr_uncompressed(store, dname, dname_len, tp, 504 kl, ttl, buf, rdlen)) { 505 log_msg(LOG_ERR, "out of memory"); 506 return 0; 507 } 508 } 509 return 1; 510} 511 512/* add the rrset to the added list */ 513static int process_add_rrset(struct ixfr_store* ixfr_store, 514 struct domain* domain, struct rrset* rrset) 515{ 516 int i; 517 for(i=0; i<rrset->rr_count; i++) { 518 if(!ixfr_store_addrr_rdatas(ixfr_store, domain_dname(domain), 519 rrset->rrs[i].type, rrset->rrs[i].klass, 520 rrset->rrs[i].ttl, rrset->rrs[i].rdatas, 521 rrset->rrs[i].rdata_count)) { 522 log_msg(LOG_ERR, "out of memory"); 523 return 0; 524 } 525 } 526 return 1; 527} 528 529/* add the RR types that are not in the marktypes list from the new zone */ 530static int process_marktypes(struct ixfr_store* store, struct zone* zone, 531 struct domain* domain, uint16_t* marktypes, size_t marktypes_used) 532{ 533 /* walk through the rrsets in the zone, if it is not in the 534 * marktypes list, then it is new and an added RRset */ 535 rrset_type* s; 536 qsort(marktypes, marktypes_used, sizeof(marktypes[0]), &sort_uint16); 537 for(s=domain->rrsets; s; s=s->next) { 538 uint16_t tp; 539 if(s->zone != zone) 540 continue; 541 tp = rrset_rrtype(s); 542 if(bsearch(&tp, marktypes, marktypes_used, sizeof(marktypes[0]), &sort_uint16)) { 543 /* the item is in the marked list, skip it */ 544 continue; 545 } 546 if(!process_add_rrset(store, domain, s)) 547 return 0; 548 } 549 return 1; 550} 551 552/* check the difference between the domain and RRs from spool */ 553static int process_diff_domain(FILE* spool, struct ixfr_create* ixfrcr, 554 struct ixfr_store* store, struct zone* zone, struct domain* domain) 555{ 556 /* Read the RR types from spool. Mark off the ones seen, 557 * later, the notseen ones from the new zone are added RRsets. 558 * For the ones not in the new zone, they are deleted RRsets. 559 * If they exist in old and new, check for RR differences. */ 560 uint32_t spool_type_count, i; 561 uint16_t marktypes[65536]; 562 size_t marktypes_used = 0; 563 if(!read_spool_u32(spool, &spool_type_count)) { 564 log_msg(LOG_ERR, "error reading file %s: %s", 565 ixfrcr->file_name, strerror(errno)); 566 return 0; 567 } 568 if(spool_type_count > sizeof(marktypes)) { 569 log_msg(LOG_ERR, "error reading file %s: spool type count " 570 "too large", ixfrcr->file_name); 571 return 0; 572 } 573 for(i=0; i<spool_type_count; i++) { 574 uint16_t tp, kl, rrcount; 575 struct rrset* rrset; 576 if(!read_spool_u16(spool, &tp) || 577 !read_spool_u16(spool, &kl) || 578 !read_spool_u16(spool, &rrcount)) { 579 log_msg(LOG_ERR, "error reading file %s: %s", 580 ixfrcr->file_name, strerror(errno)); 581 return 0; 582 } 583 /* The rrcount is within limits of sizeof(marktypes), because 584 * the uint16_t < 65536 */ 585 rrset = domain_find_rrset(domain, zone, tp); 586 if(!rrset) { 587 /* rrset in spool but not in new zone, deleted RRset */ 588 if(!process_spool_delrrset(spool, ixfrcr, store, 589 (void*)dname_name(domain_dname(domain)), 590 domain_dname(domain)->name_size, tp, kl, 591 rrcount)) 592 return 0; 593 } else { 594 /* add to the marked types, this one is present in 595 * spool */ 596 marktypes[marktypes_used++] = tp; 597 /* rrset in old and in new zone, diff the RRset */ 598 if(!process_diff_rrset(spool, ixfrcr, store, domain, 599 tp, kl, rrcount, rrset)) 600 return 0; 601 } 602 } 603 /* process markoff to see if new zone has RRsets not in spool, 604 * those are added RRsets. */ 605 if(!process_marktypes(store, zone, domain, marktypes, marktypes_used)) 606 return 0; 607 return 1; 608} 609 610/* add the RRs for the domain in new zone */ 611static int process_domain_add_RRs(struct ixfr_store* store, struct zone* zone, 612 struct domain* domain) 613{ 614 rrset_type* s; 615 for(s=domain->rrsets; s; s=s->next) { 616 if(s->zone != zone) 617 continue; 618 if(!process_add_rrset(store, domain, s)) 619 return 0; 620 } 621 return 1; 622} 623 624/* del the RRs for the domain from the spool */ 625static int process_domain_del_RRs(struct ixfr_create* ixfrcr, 626 struct ixfr_store* store, FILE* spool, uint8_t* dname, 627 size_t dname_len) 628{ 629 uint32_t spool_type_count, i; 630 if(!read_spool_u32(spool, &spool_type_count)) { 631 log_msg(LOG_ERR, "error reading file %s: %s", 632 ixfrcr->file_name, strerror(errno)); 633 return 0; 634 } 635 if(spool_type_count > 65536) { 636 log_msg(LOG_ERR, "error reading file %s: del RR spool type " 637 "count too large", ixfrcr->file_name); 638 return 0; 639 } 640 for(i=0; i<spool_type_count; i++) { 641 uint16_t tp, kl, rrcount; 642 if(!read_spool_u16(spool, &tp) || 643 !read_spool_u16(spool, &kl) || 644 !read_spool_u16(spool, &rrcount)) { 645 log_msg(LOG_ERR, "error reading file %s: %s", 646 ixfrcr->file_name, strerror(errno)); 647 return 0; 648 } 649 /* The rrcount is within reasonable limits, because 650 * the uint16_t < 65536 */ 651 if(!process_spool_delrrset(spool, ixfrcr, store, dname, 652 dname_len, tp, kl, rrcount)) 653 return 0; 654 } 655 return 1; 656} 657 658/* init the spool dname iterator */ 659static void spool_dname_iter_init(struct spool_dname_iterator* iter, 660 FILE* spool, char* file_name) 661{ 662 memset(iter, 0, sizeof(*iter)); 663 iter->spool = spool; 664 iter->file_name = file_name; 665} 666 667/* read the dname element into the buffer for the spool dname iterator */ 668static int spool_dname_iter_read(struct spool_dname_iterator* iter) 669{ 670 if(!read_spool_dname(iter->spool, iter->dname, sizeof(iter->dname), 671 &iter->dname_len)) { 672 log_msg(LOG_ERR, "error reading file %s: %s", 673 iter->file_name, strerror(errno)); 674 return 0; 675 } 676 return 1; 677} 678 679/* get the next name to operate on, that is not processed yet, 0 on failure 680 * returns okay on endoffile, check with eof for that. 681 * when done with an element, set iter->is_processed on the element. */ 682static int spool_dname_iter_next(struct spool_dname_iterator* iter) 683{ 684 if(iter->eof) 685 return 1; 686 if(!iter->read_first) { 687 /* read the first one */ 688 if(!spool_dname_iter_read(iter)) 689 return 0; 690 if(iter->dname_len == 0) 691 iter->eof = 1; 692 iter->read_first = 1; 693 iter->is_processed = 0; 694 } 695 if(!iter->is_processed) { 696 /* the current one needs processing */ 697 return 1; 698 } 699 /* read the next one */ 700 if(!spool_dname_iter_read(iter)) 701 return 0; 702 if(iter->dname_len == 0) 703 iter->eof = 1; 704 iter->is_processed = 0; 705 return 1; 706} 707 708/* check if the ixfr is too large */ 709static int ixfr_create_too_large(struct ixfr_create* ixfrcr, 710 struct ixfr_store* store) 711{ 712 if(store->cancelled) 713 return 1; 714 if(ixfrcr->max_size != 0 && 715 ixfr_data_size(store->data) > ixfrcr->max_size) { 716 if(ixfrcr->errorcmdline) { 717 log_msg(LOG_ERR, "the ixfr for %s exceeds size %u, it is not created", 718 wiredname2str(ixfrcr->zone_name), 719 (unsigned)ixfrcr->max_size); 720 } else { 721 VERBOSITY(2, (LOG_INFO, "the ixfr for %s exceeds size %u, it is not created", 722 wiredname2str(ixfrcr->zone_name), 723 (unsigned)ixfrcr->max_size)); 724 } 725 ixfr_store_cancel(store); 726 return 1; 727 } 728 return 0; 729} 730 731/* process the spool input before the domain */ 732static int process_spool_before_domain(FILE* spool, struct ixfr_create* ixfrcr, 733 struct ixfr_store* store, struct domain* domain, 734 struct spool_dname_iterator* iter, struct region* tmp_region) 735{ 736 const dname_type* dname; 737 if(ixfr_create_too_large(ixfrcr, store)) 738 return 0; 739 /* read the domains and rrsets before the domain and those are from 740 * the old zone. If the domain is equal, return to have that processed 741 * if we bypass, that means the domain does not exist, do that */ 742 while(!iter->eof) { 743 if(!spool_dname_iter_next(iter)) 744 return 0; 745 if(iter->eof) 746 break; 747 /* see if we are at, before or after the domain */ 748 dname = dname_make(tmp_region, iter->dname, 1); 749 if(!dname) { 750 log_msg(LOG_ERR, "error in dname in %s", 751 iter->file_name); 752 return 0; 753 } 754 if(dname_compare(dname, domain_dname(domain)) < 0) { 755 /* the dname is smaller than the one from the zone. 756 * it must be deleted, process it */ 757 if(!process_domain_del_RRs(ixfrcr, store, spool, 758 iter->dname, iter->dname_len)) 759 return 0; 760 iter->is_processed = 1; 761 } else { 762 /* we are at or after the domain we are looking for, 763 * done here */ 764 return 1; 765 } 766 if(ixfr_create_too_large(ixfrcr, store)) 767 return 0; 768 } 769 /* no more domains on spool, done here */ 770 return 1; 771} 772 773/* process the spool input for the domain */ 774static int process_spool_for_domain(FILE* spool, struct ixfr_create* ixfrcr, 775 struct ixfr_store* store, struct zone* zone, struct domain* domain, 776 struct spool_dname_iterator* iter, struct region* tmp_region) 777{ 778 /* process all the spool that is not the domain, that is before the 779 * domain in the new zone */ 780 if(!process_spool_before_domain(spool, ixfrcr, store, domain, iter, 781 tmp_region)) 782 return 0; 783 784 if(ixfr_create_too_large(ixfrcr, store)) 785 return 0; 786 /* are we at the correct domain now? */ 787 if(iter->eof || iter->dname_len != domain_dname(domain)->name_size || 788 memcmp(iter->dname, dname_name(domain_dname(domain)), 789 iter->dname_len) != 0) { 790 /* the domain from the new zone is not present in the old zone, 791 * the content is in the added RRs set */ 792 if(!process_domain_add_RRs(store, zone, domain)) 793 return 0; 794 return 1; 795 } 796 797 /* process the domain */ 798 /* the domain exists both in the old and new zone, 799 * check for RR differences */ 800 if(!process_diff_domain(spool, ixfrcr, store, zone, domain)) 801 return 0; 802 iter->is_processed = 1; 803 804 return 1; 805} 806 807/* process remaining spool items */ 808static int process_spool_remaining(FILE* spool, struct ixfr_create* ixfrcr, 809 struct ixfr_store* store, struct spool_dname_iterator* iter) 810{ 811 /* the remaining domain names in the spool file, that is after 812 * the last domain in the new zone. */ 813 if(ixfr_create_too_large(ixfrcr, store)) 814 return 0; 815 while(!iter->eof) { 816 if(!spool_dname_iter_next(iter)) 817 return 0; 818 if(iter->eof) 819 break; 820 /* the domain only exists in the spool, the old zone, 821 * and not in the new zone. That would be domains 822 * after the new zone domains, or there are no new 823 * zone domains */ 824 if(!process_domain_del_RRs(ixfrcr, store, spool, iter->dname, 825 iter->dname_len)) 826 return 0; 827 iter->is_processed = 1; 828 if(ixfr_create_too_large(ixfrcr, store)) 829 return 0; 830 } 831 return 1; 832} 833 834/* walk through the zone and find the differences */ 835static int ixfr_create_walk_zone(FILE* spool, struct ixfr_create* ixfrcr, 836 struct ixfr_store* store, struct zone* zone) 837{ 838 struct domain* domain; 839 struct spool_dname_iterator iter; 840 struct region* tmp_region; 841 spool_dname_iter_init(&iter, spool, ixfrcr->file_name); 842 tmp_region = region_create(xalloc, free); 843 for(domain = zone->apex; domain && domain_is_subdomain(domain, 844 zone->apex); domain = domain_next(domain)) { 845 uint32_t count = domain_count_rrsets(domain, zone); 846 if(count == 0) 847 continue; 848 849 /* the domain is a domain in the new zone */ 850 if(!process_spool_for_domain(spool, ixfrcr, store, zone, 851 domain, &iter, tmp_region)) { 852 region_destroy(tmp_region); 853 return 0; 854 } 855 region_free_all(tmp_region); 856 if(ixfr_create_too_large(ixfrcr, store)) 857 return 0; 858 } 859 if(!process_spool_remaining(spool, ixfrcr, store, &iter)) { 860 region_destroy(tmp_region); 861 return 0; 862 } 863 region_destroy(tmp_region); 864 return 1; 865} 866 867/* see if the ixfr has already been created by reading the file header 868 * of the to-be-created file, if that file already exists */ 869static int ixfr_create_already_done_serial(struct zone* zone, 870 const char* zfile, int checknew, uint32_t old_serial, 871 uint32_t new_serial) 872{ 873 uint32_t file_oldserial = 0, file_newserial = 0; 874 size_t data_size = 0; 875 if(!ixfr_read_file_header(zone->opts->name, zfile, 1, &file_oldserial, 876 &file_newserial, &data_size, 0)) { 877 /* could not read, so it was not done */ 878 return 0; 879 } 880 if(file_oldserial == old_serial && 881 (!checknew || file_newserial == new_serial)) { 882 log_msg(LOG_INFO, "IXFR already exists in file %s.ixfr, nothing to do", 883 zfile); 884 return 1; 885 } 886 return 0; 887} 888 889/* See the data size of the ixfr by reading the file header of the ixfr file */ 890static int ixfr_read_header_data_size(const char* zname, 891 const char* zfile, int file_num, size_t* data_size) 892{ 893 uint32_t file_oldserial = 0, file_newserial = 0; 894 if(!ixfr_read_file_header(zname, zfile, file_num, &file_oldserial, 895 &file_newserial, data_size, 0)) { 896 /* could not read */ 897 return 0; 898 } 899 return 1; 900} 901 902/* see if the ixfr has already been created by reading the file header 903 * of the to-be-created file, if that file already exists */ 904static int ixfr_create_already_done(struct ixfr_create* ixfrcr, 905 struct zone* zone, const char* zfile, int checknew) 906{ 907 return ixfr_create_already_done_serial(zone, zfile, checknew, 908 ixfrcr->old_serial, ixfrcr->new_serial); 909} 910 911/* store the new soa record for the ixfr */ 912static int ixfr_create_store_newsoa(struct ixfr_store* store, 913 struct zone* zone) 914{ 915 if(!zone || !zone->soa_rrset) { 916 log_msg(LOG_ERR, "error no SOA rrset"); 917 return 0; 918 } 919 if(zone->soa_rrset->rr_count == 0) { 920 log_msg(LOG_ERR, "error empty SOA rrset"); 921 return 0; 922 } 923 if(!ixfr_store_add_newsoa_rdatas(store, domain_dname(zone->apex), 924 zone->soa_rrset->rrs[0].type, zone->soa_rrset->rrs[0].klass, 925 zone->soa_rrset->rrs[0].ttl, zone->soa_rrset->rrs[0].rdatas, 926 zone->soa_rrset->rrs[0].rdata_count)) { 927 log_msg(LOG_ERR, "out of memory"); 928 return 0; 929 } 930 return 1; 931} 932 933/* initialise ixfr_create perform, open spool, read header, get serial */ 934static int ixfr_perform_init(struct ixfr_create* ixfrcr, struct zone* zone, 935 struct ixfr_store* store_mem, struct ixfr_store** store, FILE** spool) 936{ 937 *spool = fopen(ixfrcr->file_name, "r"); 938 if(!*spool) { 939 log_msg(LOG_ERR, "could not open %s for reading: %s", 940 ixfrcr->file_name, strerror(errno)); 941 return 0; 942 } 943 if(!read_spool_header(*spool, ixfrcr)) { 944 fclose(*spool); 945 return 0; 946 } 947 ixfrcr->new_serial = zone_get_current_serial(zone); 948 *store = ixfr_store_start(zone, store_mem); 949 if(!ixfr_create_store_newsoa(*store, zone)) { 950 fclose(*spool); 951 ixfr_store_free(*store); 952 return 0; 953 } 954 return 1; 955} 956 957/* rename the other ixfr files */ 958static int ixfr_create_rename_and_delete_files(const char* zname, 959 const char* zoptsname, const char* zfile, uint32_t ixfr_number, 960 size_t ixfr_size, size_t cur_data_size) 961{ 962 size_t size_in_use = cur_data_size; 963 int dest_nr_files = (int)ixfr_number, maxsizehit = 0; 964 int num = 1; 965 while(ixfr_file_exists(zfile, num)) { 966 size_t fsize = 0; 967 if(!maxsizehit) { 968 if(!ixfr_read_header_data_size(zoptsname, zfile, num, 969 &fsize) || size_in_use + fsize > ixfr_size) { 970 /* no more than this because of storage size */ 971 dest_nr_files = num; 972 maxsizehit = 1; 973 } 974 size_in_use += fsize; 975 } 976 num++; 977 } 978 num--; 979 /* num is now the number of ixfr files that exist */ 980 while(num > 0) { 981 if(num+1 > dest_nr_files) { 982 (void)ixfr_unlink_it(zname, zfile, num, 0); 983 } else { 984 if(!ixfr_rename_it(zname, zfile, num, 0, num+1, 0)) 985 return 0; 986 } 987 num--; 988 } 989 return 1; 990} 991 992/* finish up ixfr create processing */ 993static void ixfr_create_finishup(struct ixfr_create* ixfrcr, 994 struct ixfr_store* store, struct zone* zone, int append_mem, 995 struct nsd* nsd, const char* zfile, uint32_t ixfr_number) 996{ 997 char log_buf[1024], nowstr[128]; 998 /* create the log message */ 999 time_t now = time(NULL); 1000 if(store->cancelled || ixfr_create_too_large(ixfrcr, store)) { 1001 /* remove unneeded files. 1002 * since this ixfr cannot be created the others are useless. */ 1003 ixfr_delete_superfluous_files(zone, zfile, 0); 1004 return; 1005 } 1006 snprintf(nowstr, sizeof(nowstr), "%s", ctime(&now)); 1007 if(strchr(nowstr, '\n')) 1008 *strchr(nowstr, '\n') = 0; 1009 snprintf(log_buf, sizeof(log_buf), 1010 "IXFR created by NSD %s for %s %u to %u of %u bytes at time %s", 1011 PACKAGE_VERSION, wiredname2str(ixfrcr->zone_name), 1012 (unsigned)ixfrcr->old_serial, (unsigned)ixfrcr->new_serial, 1013 (unsigned)ixfr_data_size(store->data), nowstr); 1014 store->data->log_str = strdup(log_buf); 1015 if(!store->data->log_str) { 1016 log_msg(LOG_ERR, "out of memory"); 1017 ixfr_store_free(store); 1018 return; 1019 } 1020 if(!ixfr_create_rename_and_delete_files( 1021 wiredname2str(ixfrcr->zone_name), zone->opts->name, zfile, 1022 ixfr_number, ixfrcr->max_size, ixfr_data_size(store->data))) { 1023 log_msg(LOG_ERR, "could not rename other ixfr files"); 1024 ixfr_store_free(store); 1025 return; 1026 } 1027 if(!ixfr_write_file(zone, store->data, zfile, 1)) { 1028 log_msg(LOG_ERR, "could not write to file"); 1029 ixfr_store_free(store); 1030 return; 1031 } 1032 if(append_mem) { 1033 ixfr_store_finish(store, nsd, log_buf); 1034 } 1035} 1036 1037void ixfr_readup_exist(struct zone* zone, struct nsd* nsd, 1038 const char* zfile) 1039{ 1040 /* the .ixfr file already exists with the correct serial numbers 1041 * on the disk. Read up the ixfr files from the drive and put them 1042 * in memory. To match the zone that has just been read. 1043 * We can skip ixfr creation, and read up the files from the drive. 1044 * If the files on the drive are consistent, we end up with exactly 1045 * those ixfrs and that zone in memory. 1046 * Presumably, the user has used nsd-checkzone to create an IXFR 1047 * file and has put a new zone file, so we read up the data that 1048 * we should have now. 1049 * This also takes into account the config on number and size. */ 1050 ixfr_read_from_file(nsd, zone, zfile); 1051} 1052 1053int ixfr_create_perform(struct ixfr_create* ixfrcr, struct zone* zone, 1054 int append_mem, struct nsd* nsd, const char* zfile, 1055 uint32_t ixfr_number) 1056{ 1057 struct ixfr_store store_mem, *store; 1058 FILE* spool; 1059 if(!ixfr_perform_init(ixfrcr, zone, &store_mem, &store, &spool)) { 1060 (void)unlink(ixfrcr->file_name); 1061 return 0; 1062 } 1063 if(ixfrcr->new_serial == ixfrcr->old_serial || 1064 compare_serial(ixfrcr->new_serial, ixfrcr->old_serial)<0) { 1065 log_msg(LOG_ERR, "zone %s ixfr could not be created because the serial is the same or moves backwards, from %u to %u", 1066 wiredname2str(ixfrcr->zone_name), 1067 (unsigned)ixfrcr->old_serial, 1068 (unsigned)ixfrcr->new_serial); 1069 ixfr_store_cancel(store); 1070 fclose(spool); 1071 ixfr_store_free(store); 1072 (void)unlink(ixfrcr->file_name); 1073 ixfr_delete_superfluous_files(zone, zfile, 0); 1074 if(append_mem) 1075 ixfr_store_delixfrs(zone); 1076 return 0; 1077 } 1078 if(ixfr_create_already_done(ixfrcr, zone, zfile, 1)) { 1079 ixfr_store_cancel(store); 1080 fclose(spool); 1081 ixfr_store_free(store); 1082 (void)unlink(ixfrcr->file_name); 1083 if(append_mem) { 1084 ixfr_readup_exist(zone, nsd, zfile); 1085 } 1086 return 0; 1087 } 1088 1089 if(!ixfr_create_walk_zone(spool, ixfrcr, store, zone)) { 1090 fclose(spool); 1091 ixfr_store_free(store); 1092 (void)unlink(ixfrcr->file_name); 1093 ixfr_delete_superfluous_files(zone, zfile, 0); 1094 return 0; 1095 } 1096 if(store->data && !store->data->oldsoa) { 1097 log_msg(LOG_ERR, "error spool file did not contain a SOA record"); 1098 fclose(spool); 1099 ixfr_store_free(store); 1100 (void)unlink(ixfrcr->file_name); 1101 return 0; 1102 } 1103 if(!store->cancelled) 1104 ixfr_store_finish_data(store); 1105 fclose(spool); 1106 (void)unlink(ixfrcr->file_name); 1107 1108 ixfr_create_finishup(ixfrcr, store, zone, append_mem, nsd, zfile, 1109 ixfr_number); 1110 return 1; 1111} 1112 1113void ixfr_create_cancel(struct ixfr_create* ixfrcr) 1114{ 1115 if(!ixfrcr) 1116 return; 1117 (void)unlink(ixfrcr->file_name); 1118 ixfr_create_free(ixfrcr); 1119} 1120 1121int ixfr_create_from_difference(struct zone* zone, const char* zfile, 1122 int* ixfr_create_already_done_flag) 1123{ 1124 uint32_t old_serial; 1125 *ixfr_create_already_done_flag = 0; 1126 /* only if the zone is ixfr enabled */ 1127 if(!zone_is_ixfr_enabled(zone)) 1128 return 0; 1129 /* only if ixfr create is enabled */ 1130 if(!zone->opts->pattern->create_ixfr) 1131 return 0; 1132 /* only if there is a zone in memory to compare with */ 1133 if(!zone->soa_rrset || !zone->apex) 1134 return 0; 1135 1136 old_serial = zone_get_current_serial(zone); 1137 if(ixfr_create_already_done_serial(zone, zfile, 0, old_serial, 0)) { 1138 *ixfr_create_already_done_flag = 1; 1139 return 0; 1140 } 1141 1142 return 1; 1143} 1144