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