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 */ 20 static 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 */ 29 static 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 */ 38 static 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 */ 51 static 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 */ 67 static 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 */ 92 static 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 */ 111 static 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 */ 125 static 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 */ 137 static 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. */ 161 static 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 */ 194 static 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 */ 207 struct 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 */ 244 void 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 */ 254 static 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 */ 262 static 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 */ 270 static 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 */ 289 static 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 */ 323 static 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 */ 340 static 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 */ 370 static 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 */ 386 static 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 */ 398 static 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 */ 472 static 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 */ 513 static 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 */ 530 static 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 */ 553 static 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 */ 611 static 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 */ 625 static 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 */ 659 static 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 */ 668 static 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. */ 682 static 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 */ 709 static 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 */ 732 static 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 */ 774 static 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 */ 808 static 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 */ 835 static 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 */ 869 static 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 */ 890 static 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 */ 904 static 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 */ 912 static 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 */ 934 static 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, ixfrcr->old_serial, 949 ixfrcr->new_serial); 950 if(!ixfr_create_store_newsoa(*store, zone)) { 951 fclose(*spool); 952 ixfr_store_free(*store); 953 return 0; 954 } 955 return 1; 956 } 957 958 /* rename the other ixfr files */ 959 static int ixfr_create_rename_and_delete_files(const char* zname, 960 const char* zoptsname, const char* zfile, uint32_t ixfr_number, 961 size_t ixfr_size, size_t cur_data_size) 962 { 963 size_t size_in_use = cur_data_size; 964 int dest_nr_files = (int)ixfr_number, maxsizehit = 0; 965 int num = 1; 966 while(ixfr_file_exists(zfile, num)) { 967 size_t fsize = 0; 968 if(!maxsizehit) { 969 if(!ixfr_read_header_data_size(zoptsname, zfile, num, 970 &fsize) || size_in_use + fsize > ixfr_size) { 971 /* no more than this because of storage size */ 972 dest_nr_files = num; 973 maxsizehit = 1; 974 } 975 size_in_use += fsize; 976 } 977 num++; 978 } 979 num--; 980 /* num is now the number of ixfr files that exist */ 981 while(num > 0) { 982 if(num+1 > dest_nr_files) { 983 (void)ixfr_unlink_it(zname, zfile, num, 0); 984 } else { 985 if(!ixfr_rename_it(zname, zfile, num, 0, num+1, 0)) 986 return 0; 987 } 988 num--; 989 } 990 return 1; 991 } 992 993 /* finish up ixfr create processing */ 994 static void ixfr_create_finishup(struct ixfr_create* ixfrcr, 995 struct ixfr_store* store, struct zone* zone, int append_mem, 996 struct nsd* nsd, const char* zfile, uint32_t ixfr_number) 997 { 998 char log_buf[1024], nowstr[128]; 999 /* create the log message */ 1000 time_t now = time(NULL); 1001 if(store->cancelled || ixfr_create_too_large(ixfrcr, store)) { 1002 /* remove unneeded files. 1003 * since this ixfr cannot be created the others are useless. */ 1004 ixfr_delete_superfluous_files(zone, zfile, 0); 1005 return; 1006 } 1007 snprintf(nowstr, sizeof(nowstr), "%s", ctime(&now)); 1008 if(strchr(nowstr, '\n')) 1009 *strchr(nowstr, '\n') = 0; 1010 snprintf(log_buf, sizeof(log_buf), 1011 "IXFR created by NSD %s for %s %u to %u of %u bytes at time %s", 1012 PACKAGE_VERSION, wiredname2str(ixfrcr->zone_name), 1013 (unsigned)ixfrcr->old_serial, (unsigned)ixfrcr->new_serial, 1014 (unsigned)ixfr_data_size(store->data), nowstr); 1015 store->data->log_str = strdup(log_buf); 1016 if(!store->data->log_str) { 1017 log_msg(LOG_ERR, "out of memory"); 1018 ixfr_store_free(store); 1019 return; 1020 } 1021 if(!ixfr_create_rename_and_delete_files( 1022 wiredname2str(ixfrcr->zone_name), zone->opts->name, zfile, 1023 ixfr_number, ixfrcr->max_size, ixfr_data_size(store->data))) { 1024 log_msg(LOG_ERR, "could not rename other ixfr files"); 1025 ixfr_store_free(store); 1026 return; 1027 } 1028 if(!ixfr_write_file(zone, store->data, zfile, 1)) { 1029 log_msg(LOG_ERR, "could not write to file"); 1030 ixfr_store_free(store); 1031 return; 1032 } 1033 if(append_mem) { 1034 ixfr_store_finish(store, nsd, log_buf); 1035 } 1036 } 1037 1038 void ixfr_readup_exist(struct zone* zone, struct nsd* nsd, 1039 const char* zfile) 1040 { 1041 /* the .ixfr file already exists with the correct serial numbers 1042 * on the disk. Read up the ixfr files from the drive and put them 1043 * in memory. To match the zone that has just been read. 1044 * We can skip ixfr creation, and read up the files from the drive. 1045 * If the files on the drive are consistent, we end up with exactly 1046 * those ixfrs and that zone in memory. 1047 * Presumably, the user has used nsd-checkzone to create an IXFR 1048 * file and has put a new zone file, so we read up the data that 1049 * we should have now. 1050 * This also takes into account the config on number and size. */ 1051 ixfr_read_from_file(nsd, zone, zfile); 1052 } 1053 1054 int ixfr_create_perform(struct ixfr_create* ixfrcr, struct zone* zone, 1055 int append_mem, struct nsd* nsd, const char* zfile, 1056 uint32_t ixfr_number) 1057 { 1058 struct ixfr_store store_mem, *store; 1059 FILE* spool; 1060 if(!ixfr_perform_init(ixfrcr, zone, &store_mem, &store, &spool)) { 1061 (void)unlink(ixfrcr->file_name); 1062 return 0; 1063 } 1064 if(ixfrcr->new_serial == ixfrcr->old_serial || 1065 compare_serial(ixfrcr->new_serial, ixfrcr->old_serial)<0) { 1066 log_msg(LOG_ERR, "zone %s ixfr could not be created because the serial is the same or moves backwards, from %u to %u", 1067 wiredname2str(ixfrcr->zone_name), 1068 (unsigned)ixfrcr->old_serial, 1069 (unsigned)ixfrcr->new_serial); 1070 ixfr_store_cancel(store); 1071 fclose(spool); 1072 ixfr_store_free(store); 1073 (void)unlink(ixfrcr->file_name); 1074 ixfr_delete_superfluous_files(zone, zfile, 0); 1075 if(append_mem) 1076 ixfr_store_delixfrs(zone); 1077 return 0; 1078 } 1079 if(ixfr_create_already_done(ixfrcr, zone, zfile, 1)) { 1080 ixfr_store_cancel(store); 1081 fclose(spool); 1082 ixfr_store_free(store); 1083 (void)unlink(ixfrcr->file_name); 1084 if(append_mem) { 1085 ixfr_readup_exist(zone, nsd, zfile); 1086 } 1087 return 0; 1088 } 1089 1090 if(!ixfr_create_walk_zone(spool, ixfrcr, store, zone)) { 1091 fclose(spool); 1092 ixfr_store_free(store); 1093 (void)unlink(ixfrcr->file_name); 1094 ixfr_delete_superfluous_files(zone, zfile, 0); 1095 return 0; 1096 } 1097 if(store->data && !store->data->oldsoa) { 1098 log_msg(LOG_ERR, "error spool file did not contain a SOA record"); 1099 fclose(spool); 1100 ixfr_store_free(store); 1101 (void)unlink(ixfrcr->file_name); 1102 return 0; 1103 } 1104 if(!store->cancelled) 1105 ixfr_store_finish_data(store); 1106 fclose(spool); 1107 (void)unlink(ixfrcr->file_name); 1108 1109 ixfr_create_finishup(ixfrcr, store, zone, append_mem, nsd, zfile, 1110 ixfr_number); 1111 return 1; 1112 } 1113 1114 void ixfr_create_cancel(struct ixfr_create* ixfrcr) 1115 { 1116 if(!ixfrcr) 1117 return; 1118 (void)unlink(ixfrcr->file_name); 1119 ixfr_create_free(ixfrcr); 1120 } 1121 1122 int ixfr_create_from_difference(struct zone* zone, const char* zfile, 1123 int* ixfr_create_already_done_flag) 1124 { 1125 uint32_t old_serial; 1126 *ixfr_create_already_done_flag = 0; 1127 /* only if the zone is ixfr enabled */ 1128 if(!zone_is_ixfr_enabled(zone)) 1129 return 0; 1130 /* only if ixfr create is enabled */ 1131 if(!zone->opts->pattern->create_ixfr) 1132 return 0; 1133 /* only if there is a zone in memory to compare with */ 1134 if(!zone->soa_rrset || !zone->apex) 1135 return 0; 1136 1137 old_serial = zone_get_current_serial(zone); 1138 if(ixfr_create_already_done_serial(zone, zfile, 0, old_serial, 0)) { 1139 *ixfr_create_already_done_flag = 1; 1140 return 0; 1141 } 1142 1143 return 1; 1144 } 1145