Home | History | Annotate | Line # | Download | only in dist
      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