xref: /openbsd-src/usr.sbin/nsd/ixfrcreate.c (revision b71395ea3d4830c6fd338870b804059761b8292d)
14564029fSflorian /*
24564029fSflorian  * ixfrcreate.c -- generating IXFR differences from zone files.
34564029fSflorian  *
44564029fSflorian  * Copyright (c) 2021, NLnet Labs. All rights reserved.
54564029fSflorian  *
64564029fSflorian  * See LICENSE for the license.
74564029fSflorian  *
84564029fSflorian  */
94564029fSflorian 
104564029fSflorian #include "config.h"
114564029fSflorian #include <stdio.h>
124564029fSflorian #include <errno.h>
134564029fSflorian #include <unistd.h>
144564029fSflorian #include "ixfrcreate.h"
154564029fSflorian #include "namedb.h"
164564029fSflorian #include "ixfr.h"
174564029fSflorian #include "options.h"
184564029fSflorian 
194564029fSflorian /* spool a uint16_t to file */
spool_u16(FILE * out,uint16_t val)204564029fSflorian static int spool_u16(FILE* out, uint16_t val)
214564029fSflorian {
224564029fSflorian 	if(!fwrite(&val, sizeof(val), 1, out)) {
234564029fSflorian 		return 0;
244564029fSflorian 	}
254564029fSflorian 	return 1;
264564029fSflorian }
274564029fSflorian 
284564029fSflorian /* spool a uint32_t to file */
spool_u32(FILE * out,uint32_t val)294564029fSflorian static int spool_u32(FILE* out, uint32_t val)
304564029fSflorian {
314564029fSflorian 	if(!fwrite(&val, sizeof(val), 1, out)) {
324564029fSflorian 		return 0;
334564029fSflorian 	}
344564029fSflorian 	return 1;
354564029fSflorian }
364564029fSflorian 
374564029fSflorian /* spool dname to file */
spool_dname(FILE * out,dname_type * dname)384564029fSflorian static int spool_dname(FILE* out, dname_type* dname)
394564029fSflorian {
404564029fSflorian 	uint16_t namelen = dname->name_size;
414564029fSflorian 	if(!fwrite(&namelen, sizeof(namelen), 1, out)) {
424564029fSflorian 		return 0;
434564029fSflorian 	}
444564029fSflorian 	if(!fwrite(dname_name(dname), namelen, 1, out)) {
454564029fSflorian 		return 0;
464564029fSflorian 	}
474564029fSflorian 	return 1;
484564029fSflorian }
494564029fSflorian 
504564029fSflorian /* calculate the rdatalen of an RR */
rr_rdatalen_uncompressed(rr_type * rr)514564029fSflorian static size_t rr_rdatalen_uncompressed(rr_type* rr)
524564029fSflorian {
534564029fSflorian 	int i;
544564029fSflorian 	size_t rdlen_uncompressed = 0;
554564029fSflorian 	for(i=0; i<rr->rdata_count; i++) {
564564029fSflorian 		if(rdata_atom_is_domain(rr->type, i)) {
574564029fSflorian 			rdlen_uncompressed += domain_dname(rr->rdatas[i].domain)
584564029fSflorian 				->name_size;
594564029fSflorian 		} else {
604564029fSflorian 			rdlen_uncompressed += rr->rdatas[i].data[0];
614564029fSflorian 		}
624564029fSflorian 	}
634564029fSflorian 	return rdlen_uncompressed;
644564029fSflorian }
654564029fSflorian 
664564029fSflorian /* spool the data for one rr into the file */
spool_rr_data(FILE * out,rr_type * rr)674564029fSflorian static int spool_rr_data(FILE* out, rr_type* rr)
684564029fSflorian {
694564029fSflorian 	int i;
704564029fSflorian 	uint16_t rdlen;
714564029fSflorian 	if(!spool_u32(out, rr->ttl))
724564029fSflorian 		return 0;
734564029fSflorian 	rdlen = rr_rdatalen_uncompressed(rr);
744564029fSflorian 	if(!spool_u16(out, rdlen))
754564029fSflorian 		return 0;
764564029fSflorian 	for(i=0; i<rr->rdata_count; i++) {
774564029fSflorian 		if(rdata_atom_is_domain(rr->type, i)) {
784564029fSflorian 			if(!fwrite(dname_name(domain_dname(
794564029fSflorian 				rr->rdatas[i].domain)), domain_dname(
804564029fSflorian 				rr->rdatas[i].domain)->name_size, 1, out))
814564029fSflorian 				return 0;
824564029fSflorian 		} else {
834564029fSflorian 			if(!fwrite(&rr->rdatas[i].data[1],
844564029fSflorian 				rr->rdatas[i].data[0], 1, out))
854564029fSflorian 				return 0;
864564029fSflorian 		}
874564029fSflorian 	}
884564029fSflorian 	return 1;
894564029fSflorian }
904564029fSflorian 
914564029fSflorian /* spool one rrset to file */
spool_rrset(FILE * out,rrset_type * rrset)924564029fSflorian static int spool_rrset(FILE* out, rrset_type* rrset)
934564029fSflorian {
944564029fSflorian 	int i;
954564029fSflorian 	if(rrset->rr_count == 0)
964564029fSflorian 		return 1;
974564029fSflorian 	if(!spool_u16(out, rrset->rrs[0].type))
984564029fSflorian 		return 0;
994564029fSflorian 	if(!spool_u16(out, rrset->rrs[0].klass))
1004564029fSflorian 		return 0;
1014564029fSflorian 	if(!spool_u16(out, rrset->rr_count))
1024564029fSflorian 		return 0;
1034564029fSflorian 	for(i=0; i<rrset->rr_count; i++) {
1044564029fSflorian 		if(!spool_rr_data(out, &rrset->rrs[i]))
1054564029fSflorian 			return 0;
1064564029fSflorian 	}
1074564029fSflorian 	return 1;
1084564029fSflorian }
1094564029fSflorian 
1104564029fSflorian /* spool rrsets to file */
spool_rrsets(FILE * out,rrset_type * rrsets,struct zone * zone)1114564029fSflorian static int spool_rrsets(FILE* out, rrset_type* rrsets, struct zone* zone)
1124564029fSflorian {
1134564029fSflorian 	rrset_type* s;
1144564029fSflorian 	for(s=rrsets; s; s=s->next) {
1154564029fSflorian 		if(s->zone != zone)
1164564029fSflorian 			continue;
1174564029fSflorian 		if(!spool_rrset(out, s)) {
1184564029fSflorian 			return 0;
1194564029fSflorian 		}
1204564029fSflorian 	}
1214564029fSflorian 	return 1;
1224564029fSflorian }
1234564029fSflorian 
1244564029fSflorian /* count number of rrsets for a domain */
domain_count_rrsets(domain_type * domain,zone_type * zone)1254564029fSflorian static size_t domain_count_rrsets(domain_type* domain, zone_type* zone)
1264564029fSflorian {
1274564029fSflorian 	rrset_type* s;
1284564029fSflorian 	size_t count = 0;
1294564029fSflorian 	for(s=domain->rrsets; s; s=s->next) {
1304564029fSflorian 		if(s->zone == zone)
1314564029fSflorian 			count++;
1324564029fSflorian 	}
1334564029fSflorian 	return count;
1344564029fSflorian }
1354564029fSflorian 
1364564029fSflorian /* spool the domain names to file, each one in turn. end with enddelimiter */
spool_domains(FILE * out,struct zone * zone)1374564029fSflorian static int spool_domains(FILE* out, struct zone* zone)
1384564029fSflorian {
1394564029fSflorian 	domain_type* domain;
1404564029fSflorian 	for(domain = zone->apex; domain && domain_is_subdomain(domain,
1414564029fSflorian 		zone->apex); domain = domain_next(domain)) {
1424564029fSflorian 		uint32_t count = domain_count_rrsets(domain, zone);
1434564029fSflorian 		if(count == 0)
1444564029fSflorian 			continue;
1454564029fSflorian 		/* write the name */
1464564029fSflorian 		if(!spool_dname(out, domain_dname(domain)))
1474564029fSflorian 			return 0;
1484564029fSflorian 		if(!spool_u32(out, count))
1494564029fSflorian 			return 0;
1504564029fSflorian 		/* write the rrsets */
1514564029fSflorian 		if(!spool_rrsets(out, domain->rrsets, zone))
1524564029fSflorian 			return 0;
1534564029fSflorian 	}
1544564029fSflorian 	/* the end delimiter is a 0 length. domain names are not zero length */
1554564029fSflorian 	if(!spool_u16(out, 0))
1564564029fSflorian 		return 0;
1574564029fSflorian 	return 1;
1584564029fSflorian }
1594564029fSflorian 
1604564029fSflorian /* spool the namedb zone to the file. print error on failure. */
spool_zone_to_file(struct zone * zone,char * file_name,uint32_t serial)1614564029fSflorian static int spool_zone_to_file(struct zone* zone, char* file_name,
1624564029fSflorian 	uint32_t serial)
1634564029fSflorian {
1644564029fSflorian 	FILE* out;
1654564029fSflorian 	out = fopen(file_name, "w");
1664564029fSflorian 	if(!out) {
1674564029fSflorian 		log_msg(LOG_ERR, "could not open %s for writing: %s",
1684564029fSflorian 			file_name, strerror(errno));
1694564029fSflorian 		return 0;
1704564029fSflorian 	}
1714564029fSflorian 	if(!spool_dname(out, domain_dname(zone->apex))) {
1724564029fSflorian 		log_msg(LOG_ERR, "could not write %s: %s",
1734564029fSflorian 			file_name, strerror(errno));
1743f21e8ccSflorian 		fclose(out);
1754564029fSflorian 		return 0;
1764564029fSflorian 	}
1774564029fSflorian 	if(!spool_u32(out, serial)) {
1784564029fSflorian 		log_msg(LOG_ERR, "could not write %s: %s",
1794564029fSflorian 			file_name, strerror(errno));
1803f21e8ccSflorian 		fclose(out);
1814564029fSflorian 		return 0;
1824564029fSflorian 	}
1834564029fSflorian 	if(!spool_domains(out, zone)) {
1844564029fSflorian 		log_msg(LOG_ERR, "could not write %s: %s",
1854564029fSflorian 			file_name, strerror(errno));
1863f21e8ccSflorian 		fclose(out);
1874564029fSflorian 		return 0;
1884564029fSflorian 	}
1894564029fSflorian 	fclose(out);
1904564029fSflorian 	return 1;
1914564029fSflorian }
1924564029fSflorian 
1934564029fSflorian /* create ixfr spool file name */
create_ixfr_spool_name(struct ixfr_create * ixfrcr,const char * zfile)1944564029fSflorian static int create_ixfr_spool_name(struct ixfr_create* ixfrcr,
1954564029fSflorian 	const char* zfile)
1964564029fSflorian {
1974564029fSflorian 	char buf[1024];
1984564029fSflorian 	snprintf(buf, sizeof(buf), "%s.spoolzone.%u", zfile,
1994564029fSflorian 		(unsigned)getpid());
2004564029fSflorian 	ixfrcr->file_name = strdup(buf);
2014564029fSflorian 	if(!ixfrcr->file_name)
2024564029fSflorian 		return 0;
2034564029fSflorian 	return 1;
2044564029fSflorian }
2054564029fSflorian 
2064564029fSflorian /* start ixfr creation */
ixfr_create_start(struct zone * zone,const char * zfile,uint64_t ixfr_size,int errorcmdline)2074564029fSflorian struct ixfr_create* ixfr_create_start(struct zone* zone, const char* zfile,
2084564029fSflorian 	uint64_t ixfr_size, int errorcmdline)
2094564029fSflorian {
2104564029fSflorian 	struct ixfr_create* ixfrcr = (struct ixfr_create*)calloc(1,
2114564029fSflorian 		sizeof(*ixfrcr));
2124564029fSflorian 	if(!ixfrcr) {
2134564029fSflorian 		log_msg(LOG_ERR, "malloc failure");
2144564029fSflorian 		return NULL;
2154564029fSflorian 	}
2164564029fSflorian 	ixfrcr->zone_name_len = domain_dname(zone->apex)->name_size;
2174564029fSflorian 	ixfrcr->zone_name = (uint8_t*)malloc(ixfrcr->zone_name_len);
2184564029fSflorian 	if(!ixfrcr->zone_name) {
2194564029fSflorian 		free(ixfrcr);
2204564029fSflorian 		log_msg(LOG_ERR, "malloc failure");
2214564029fSflorian 		return NULL;
2224564029fSflorian 	}
2234564029fSflorian 	memmove(ixfrcr->zone_name, dname_name(domain_dname(zone->apex)),
2244564029fSflorian 		ixfrcr->zone_name_len);
2254564029fSflorian 
2264564029fSflorian 	if(!create_ixfr_spool_name(ixfrcr, zfile)) {
2274564029fSflorian 		ixfr_create_free(ixfrcr);
2284564029fSflorian 		log_msg(LOG_ERR, "malloc failure");
2294564029fSflorian 		return NULL;
2304564029fSflorian 	}
2314564029fSflorian 	ixfrcr->old_serial = zone_get_current_serial(zone);
2324564029fSflorian 	if(!spool_zone_to_file(zone, ixfrcr->file_name, ixfrcr->old_serial)) {
2334564029fSflorian 		ixfr_create_free(ixfrcr);
2344564029fSflorian 		return NULL;
2354564029fSflorian 	}
2364564029fSflorian 	if(zone->opts && zone->opts->pattern)
2374564029fSflorian 		ixfrcr->max_size = (size_t)zone->opts->pattern->ixfr_size;
2384564029fSflorian 	else	ixfrcr->max_size = (size_t)ixfr_size;
2394564029fSflorian 	ixfrcr->errorcmdline = errorcmdline;
2404564029fSflorian 	return ixfrcr;
2414564029fSflorian }
2424564029fSflorian 
2434564029fSflorian /* free ixfr create */
ixfr_create_free(struct ixfr_create * ixfrcr)2444564029fSflorian void ixfr_create_free(struct ixfr_create* ixfrcr)
2454564029fSflorian {
2464564029fSflorian 	if(!ixfrcr)
2474564029fSflorian 		return;
2484564029fSflorian 	free(ixfrcr->file_name);
2494564029fSflorian 	free(ixfrcr->zone_name);
2504564029fSflorian 	free(ixfrcr);
2514564029fSflorian }
2524564029fSflorian 
2534564029fSflorian /* read uint16_t from spool */
read_spool_u16(FILE * spool,uint16_t * val)2544564029fSflorian static int read_spool_u16(FILE* spool, uint16_t* val)
2554564029fSflorian {
2563f21e8ccSflorian 	if(fread(val, sizeof(*val), 1, spool) < 1)
2574564029fSflorian 		return 0;
2584564029fSflorian 	return 1;
2594564029fSflorian }
2604564029fSflorian 
2614564029fSflorian /* read uint32_t from spool */
read_spool_u32(FILE * spool,uint32_t * val)2624564029fSflorian static int read_spool_u32(FILE* spool, uint32_t* val)
2634564029fSflorian {
2643f21e8ccSflorian 	if(fread(val, sizeof(*val), 1, spool) < 1)
2654564029fSflorian 		return 0;
2664564029fSflorian 	return 1;
2674564029fSflorian }
2684564029fSflorian 
2694564029fSflorian /* read dname from spool */
read_spool_dname(FILE * spool,uint8_t * buf,size_t buflen,size_t * dname_len)2704564029fSflorian static int read_spool_dname(FILE* spool, uint8_t* buf, size_t buflen,
2714564029fSflorian 	size_t* dname_len)
2724564029fSflorian {
2734564029fSflorian 	uint16_t len;
2743f21e8ccSflorian 	if(fread(&len, sizeof(len), 1, spool) < 1)
2754564029fSflorian 		return 0;
2764564029fSflorian 	if(len > buflen) {
2774564029fSflorian 		log_msg(LOG_ERR, "dname too long");
2784564029fSflorian 		return 0;
2794564029fSflorian 	}
2804564029fSflorian 	if(len > 0) {
2813f21e8ccSflorian 		if(fread(buf, len, 1, spool) < 1)
2824564029fSflorian 			return 0;
2834564029fSflorian 	}
2844564029fSflorian 	*dname_len = len;
2854564029fSflorian 	return 1;
2864564029fSflorian }
2874564029fSflorian 
2884564029fSflorian /* read and check the spool file header */
read_spool_header(FILE * spool,struct ixfr_create * ixfrcr)2894564029fSflorian static int read_spool_header(FILE* spool, struct ixfr_create* ixfrcr)
2904564029fSflorian {
2914564029fSflorian 	uint8_t dname[MAXDOMAINLEN+1];
2924564029fSflorian 	size_t dname_len;
2934564029fSflorian 	uint32_t serial;
2944564029fSflorian 	/* read apex */
2954564029fSflorian 	if(!read_spool_dname(spool, dname, sizeof(dname), &dname_len)) {
2964564029fSflorian 		log_msg(LOG_ERR, "error reading file %s: %s",
2974564029fSflorian 			ixfrcr->file_name, strerror(errno));
2984564029fSflorian 		return 0;
2994564029fSflorian 	}
3004564029fSflorian 	/* read serial */
3014564029fSflorian 	if(!read_spool_u32(spool, &serial)) {
3024564029fSflorian 		log_msg(LOG_ERR, "error reading file %s: %s",
3034564029fSflorian 			ixfrcr->file_name, strerror(errno));
3044564029fSflorian 		return 0;
3054564029fSflorian 	}
3064564029fSflorian 
3074564029fSflorian 	/* check */
3084564029fSflorian 	if(ixfrcr->zone_name_len != dname_len ||
3094564029fSflorian 		memcmp(ixfrcr->zone_name, dname, ixfrcr->zone_name_len) != 0) {
3104564029fSflorian 		log_msg(LOG_ERR, "error file %s does not contain the correct zone apex",
3114564029fSflorian 			ixfrcr->file_name);
3124564029fSflorian 		return 0;
3134564029fSflorian 	}
3144564029fSflorian 	if(ixfrcr->old_serial != serial) {
3154564029fSflorian 		log_msg(LOG_ERR, "error file %s does not contain the correct zone serial",
3164564029fSflorian 			ixfrcr->file_name);
3174564029fSflorian 		return 0;
3184564029fSflorian 	}
3194564029fSflorian 	return 1;
3204564029fSflorian }
3214564029fSflorian 
3224564029fSflorian /* store the old soa record when we encounter it on the spool */
process_store_oldsoa(struct ixfr_store * store,uint8_t * dname,size_t dname_len,uint16_t tp,uint16_t kl,uint32_t ttl,uint8_t * buf,uint16_t rdlen)3234564029fSflorian static int process_store_oldsoa(struct ixfr_store* store, uint8_t* dname,
3244564029fSflorian 	size_t dname_len, uint16_t tp, uint16_t kl, uint32_t ttl, uint8_t* buf,
3254564029fSflorian 	uint16_t rdlen)
3264564029fSflorian {
3274564029fSflorian 	if(store->data->oldsoa) {
3284564029fSflorian 		log_msg(LOG_ERR, "error spool contains multiple SOA records");
3294564029fSflorian 		return 0;
3304564029fSflorian 	}
3314564029fSflorian 	if(!ixfr_store_oldsoa_uncompressed(store, dname, dname_len, tp, kl,
3324564029fSflorian 		ttl, buf, rdlen)) {
3334564029fSflorian 		log_msg(LOG_ERR, "out of memory");
3344564029fSflorian 		return 0;
3354564029fSflorian 	}
3364564029fSflorian 	return 1;
3374564029fSflorian }
3384564029fSflorian 
3394564029fSflorian /* see if rdata matches, true if equal */
rdata_match(struct rr * rr,uint8_t * rdata,uint16_t rdlen)3404564029fSflorian static int rdata_match(struct rr* rr, uint8_t* rdata, uint16_t rdlen)
3414564029fSflorian {
3424564029fSflorian 	size_t rdpos = 0;
3434564029fSflorian 	int i;
3444564029fSflorian 	for(i=0; i<rr->rdata_count; i++) {
3454564029fSflorian 		if(rdata_atom_is_domain(rr->type, i)) {
3464564029fSflorian 			if(rdpos + domain_dname(rr->rdatas[i].domain)->name_size
3474564029fSflorian 				> rdlen)
3484564029fSflorian 				return 0;
3494564029fSflorian 			if(memcmp(rdata+rdpos,
3504564029fSflorian 				dname_name(domain_dname(rr->rdatas[i].domain)),
3514564029fSflorian 				domain_dname(rr->rdatas[i].domain)->name_size)
3524564029fSflorian 				!= 0)
3534564029fSflorian 				return 0;
3544564029fSflorian 			rdpos += domain_dname(rr->rdatas[i].domain)->name_size;
3554564029fSflorian 		} else {
3564564029fSflorian 			if(rdpos + rr->rdatas[i].data[0] > rdlen)
3574564029fSflorian 				return 0;
3584564029fSflorian 			if(memcmp(rdata+rdpos, &rr->rdatas[i].data[1],
3594564029fSflorian 				rr->rdatas[i].data[0]) != 0)
3604564029fSflorian 				return 0;
3614564029fSflorian 			rdpos += rr->rdatas[i].data[0];
3624564029fSflorian 		}
3634564029fSflorian 	}
3644564029fSflorian 	if(rdpos != rdlen)
3654564029fSflorian 		return 0;
3664564029fSflorian 	return 1;
3674564029fSflorian }
3684564029fSflorian 
3694564029fSflorian /* find an rdata in an rrset, true if found and sets index found */
rrset_find_rdata(struct rrset * rrset,uint32_t ttl,uint8_t * rdata,uint16_t rdlen,uint16_t * index)3704564029fSflorian static int rrset_find_rdata(struct rrset* rrset, uint32_t ttl, uint8_t* rdata,
3714564029fSflorian 	uint16_t rdlen, uint16_t* index)
3724564029fSflorian {
3734564029fSflorian 	int i;
3744564029fSflorian 	for(i=0; i<rrset->rr_count; i++) {
3754564029fSflorian 		if(rrset->rrs[i].ttl != ttl)
3764564029fSflorian 			continue;
3774564029fSflorian 		if(rdata_match(&rrset->rrs[i], rdata, rdlen)) {
3784564029fSflorian 			*index = i;
3794564029fSflorian 			return 1;
3804564029fSflorian 		}
3814564029fSflorian 	}
3824564029fSflorian 	return 0;
3834564029fSflorian }
3844564029fSflorian 
3854564029fSflorian /* sort comparison for uint16 elements */
sort_uint16(const void * x,const void * y)3864564029fSflorian static int sort_uint16(const void* x, const void* y)
3874564029fSflorian {
3884564029fSflorian 	const uint16_t* ax = (const uint16_t*)x;
3894564029fSflorian 	const uint16_t* ay = (const uint16_t*)y;
3904564029fSflorian 	if(*ax < *ay)
3914564029fSflorian 		return -1;
3924564029fSflorian 	if(*ax > *ay)
3934564029fSflorian 		return 1;
3944564029fSflorian 	return 0;
3954564029fSflorian }
3964564029fSflorian 
3974564029fSflorian /* spool read an rrset, it is a deleted RRset */
process_diff_rrset(FILE * spool,struct ixfr_create * ixfrcr,struct ixfr_store * store,struct domain * domain,uint16_t tp,uint16_t kl,uint16_t rrcount,struct rrset * rrset)3984564029fSflorian static int process_diff_rrset(FILE* spool, struct ixfr_create* ixfrcr,
3994564029fSflorian 	struct ixfr_store* store, struct domain* domain,
4004564029fSflorian 	uint16_t tp, uint16_t kl, uint16_t rrcount, struct rrset* rrset)
4014564029fSflorian {
4024564029fSflorian 	/* read RRs from file and see if they are added, deleted or in both */
4034564029fSflorian 	uint8_t buf[MAX_RDLENGTH];
4044564029fSflorian 	uint16_t marked[65536];
4054564029fSflorian 	size_t marked_num = 0, atmarked;
4064564029fSflorian 	int i;
4074564029fSflorian 	for(i=0; i<rrcount; i++) {
4084564029fSflorian 		uint16_t rdlen, index;
4094564029fSflorian 		uint32_t ttl;
4104564029fSflorian 		if(!read_spool_u32(spool, &ttl) ||
4114564029fSflorian 		   !read_spool_u16(spool, &rdlen)) {
4124564029fSflorian 			log_msg(LOG_ERR, "error reading file %s: %s",
4134564029fSflorian 				ixfrcr->file_name, strerror(errno));
4144564029fSflorian 			return 0;
4154564029fSflorian 		}
4164564029fSflorian 		/* because rdlen is uint16_t always smaller than sizeof(buf)*/
4173f21e8ccSflorian #pragma GCC diagnostic push
4183f21e8ccSflorian #pragma GCC diagnostic ignored "-Wtype-limits"
4193f21e8ccSflorian 		assert(rdlen <= sizeof(buf));
4203f21e8ccSflorian #pragma GCC diagnostic pop
4213f21e8ccSflorian 		if(fread(buf, rdlen, 1, spool) < 1) {
4224564029fSflorian 			log_msg(LOG_ERR, "error reading file %s: %s",
4234564029fSflorian 				ixfrcr->file_name, strerror(errno));
4244564029fSflorian 			return 0;
4254564029fSflorian 		}
4264564029fSflorian 		if(tp == TYPE_SOA) {
4274564029fSflorian 			if(!process_store_oldsoa(store,
4284564029fSflorian 				(void*)dname_name(domain_dname(domain)),
4294564029fSflorian 				domain_dname(domain)->name_size, tp, kl, ttl,
4304564029fSflorian 				buf, rdlen))
4314564029fSflorian 				return 0;
4324564029fSflorian 		}
4334564029fSflorian 		/* see if the rr is in the RRset */
4344564029fSflorian 		if(rrset_find_rdata(rrset, ttl, buf, rdlen, &index)) {
4354564029fSflorian 			/* it is in both, mark it */
4364564029fSflorian 			marked[marked_num++] = index;
4374564029fSflorian 		} else {
4384564029fSflorian 			/* not in new rrset, but only on spool, it is
4394564029fSflorian 			 * a deleted RR */
4404564029fSflorian 			if(!ixfr_store_delrr_uncompressed(store,
4414564029fSflorian 				(void*)dname_name(domain_dname(domain)),
4424564029fSflorian 				domain_dname(domain)->name_size,
4434564029fSflorian 				tp, kl, ttl, buf, rdlen)) {
4444564029fSflorian 				log_msg(LOG_ERR, "out of memory");
4454564029fSflorian 				return 0;
4464564029fSflorian 			}
4474564029fSflorian 		}
4484564029fSflorian 	}
4494564029fSflorian 	/* now that we are done, see if RRs in the rrset are not marked,
4504564029fSflorian 	 * and thus are new rrs that are added */
4514564029fSflorian 	qsort(marked, marked_num, sizeof(marked[0]), &sort_uint16);
4524564029fSflorian 	atmarked = 0;
4534564029fSflorian 	for(i=0; i<rrset->rr_count; i++) {
4544564029fSflorian 		if(atmarked < marked_num && marked[atmarked] == i) {
4554564029fSflorian 			/* the item is in the marked list, skip it */
4564564029fSflorian 			atmarked++;
4574564029fSflorian 			continue;
4584564029fSflorian 		}
4594564029fSflorian 		/* not in the marked list, the RR is added */
4604564029fSflorian 		if(!ixfr_store_addrr_rdatas(store, domain_dname(domain),
4614564029fSflorian 			rrset->rrs[i].type, rrset->rrs[i].klass,
4624564029fSflorian 			rrset->rrs[i].ttl, rrset->rrs[i].rdatas,
4634564029fSflorian 			rrset->rrs[i].rdata_count)) {
4644564029fSflorian 			log_msg(LOG_ERR, "out of memory");
4654564029fSflorian 			return 0;
4664564029fSflorian 		}
4674564029fSflorian 	}
4684564029fSflorian 	return 1;
4694564029fSflorian }
4704564029fSflorian 
4714564029fSflorian /* spool read an rrset, it is a deleted RRset */
process_spool_delrrset(FILE * spool,struct ixfr_create * ixfrcr,struct ixfr_store * store,uint8_t * dname,size_t dname_len,uint16_t tp,uint16_t kl,uint16_t rrcount)4724564029fSflorian static int process_spool_delrrset(FILE* spool, struct ixfr_create* ixfrcr,
4734564029fSflorian 	struct ixfr_store* store, uint8_t* dname, size_t dname_len,
4744564029fSflorian 	uint16_t tp, uint16_t kl, uint16_t rrcount)
4754564029fSflorian {
4764564029fSflorian 	/* read the RRs from file and add to del list. */
4774564029fSflorian 	uint8_t buf[MAX_RDLENGTH];
4784564029fSflorian 	int i;
4794564029fSflorian 	for(i=0; i<rrcount; i++) {
4804564029fSflorian 		uint16_t rdlen;
4814564029fSflorian 		uint32_t ttl;
4824564029fSflorian 		if(!read_spool_u32(spool, &ttl) ||
4834564029fSflorian 		   !read_spool_u16(spool, &rdlen)) {
4844564029fSflorian 			log_msg(LOG_ERR, "error reading file %s: %s",
4854564029fSflorian 				ixfrcr->file_name, strerror(errno));
4864564029fSflorian 			return 0;
4874564029fSflorian 		}
4884564029fSflorian 		/* because rdlen is uint16_t always smaller than sizeof(buf)*/
4893f21e8ccSflorian #pragma GCC diagnostic push
4903f21e8ccSflorian #pragma GCC diagnostic ignored "-Wtype-limits"
4913f21e8ccSflorian 		assert(rdlen <= sizeof(buf));
4923f21e8ccSflorian #pragma GCC diagnostic pop
4933f21e8ccSflorian 		if(fread(buf, rdlen, 1, spool) < 1) {
4944564029fSflorian 			log_msg(LOG_ERR, "error reading file %s: %s",
4954564029fSflorian 				ixfrcr->file_name, strerror(errno));
4964564029fSflorian 			return 0;
4974564029fSflorian 		}
4984564029fSflorian 		if(tp == TYPE_SOA) {
4994564029fSflorian 			if(!process_store_oldsoa(store, dname, dname_len,
5004564029fSflorian 				tp, kl, ttl, buf, rdlen))
5014564029fSflorian 				return 0;
5024564029fSflorian 		}
5034564029fSflorian 		if(!ixfr_store_delrr_uncompressed(store, dname, dname_len, tp,
5044564029fSflorian 			kl, ttl, buf, rdlen)) {
5054564029fSflorian 			log_msg(LOG_ERR, "out of memory");
5064564029fSflorian 			return 0;
5074564029fSflorian 		}
5084564029fSflorian 	}
5094564029fSflorian 	return 1;
5104564029fSflorian }
5114564029fSflorian 
5124564029fSflorian /* add the rrset to the added list */
process_add_rrset(struct ixfr_store * ixfr_store,struct domain * domain,struct rrset * rrset)5134564029fSflorian static int process_add_rrset(struct ixfr_store* ixfr_store,
5144564029fSflorian 	struct domain* domain, struct rrset* rrset)
5154564029fSflorian {
5164564029fSflorian 	int i;
5174564029fSflorian 	for(i=0; i<rrset->rr_count; i++) {
5184564029fSflorian 		if(!ixfr_store_addrr_rdatas(ixfr_store, domain_dname(domain),
5194564029fSflorian 			rrset->rrs[i].type, rrset->rrs[i].klass,
5204564029fSflorian 			rrset->rrs[i].ttl, rrset->rrs[i].rdatas,
5214564029fSflorian 			rrset->rrs[i].rdata_count)) {
5224564029fSflorian 			log_msg(LOG_ERR, "out of memory");
5234564029fSflorian 			return 0;
5244564029fSflorian 		}
5254564029fSflorian 	}
5264564029fSflorian 	return 1;
5274564029fSflorian }
5284564029fSflorian 
5294564029fSflorian /* add the RR types that are not in the marktypes list from the new zone */
process_marktypes(struct ixfr_store * store,struct zone * zone,struct domain * domain,uint16_t * marktypes,size_t marktypes_used)5304564029fSflorian static int process_marktypes(struct ixfr_store* store, struct zone* zone,
5314564029fSflorian 	struct domain* domain, uint16_t* marktypes, size_t marktypes_used)
5324564029fSflorian {
5334564029fSflorian 	/* walk through the rrsets in the zone, if it is not in the
5344564029fSflorian 	 * marktypes list, then it is new and an added RRset */
5354564029fSflorian 	rrset_type* s;
5364564029fSflorian 	qsort(marktypes, marktypes_used, sizeof(marktypes[0]), &sort_uint16);
5374564029fSflorian 	for(s=domain->rrsets; s; s=s->next) {
5384564029fSflorian 		uint16_t tp;
5394564029fSflorian 		if(s->zone != zone)
5404564029fSflorian 			continue;
5414564029fSflorian 		tp = rrset_rrtype(s);
5423efee2e1Sflorian 		if(bsearch(&tp, marktypes, marktypes_used, sizeof(marktypes[0]), &sort_uint16)) {
5434564029fSflorian 			/* the item is in the marked list, skip it */
5444564029fSflorian 			continue;
5454564029fSflorian 		}
5464564029fSflorian 		if(!process_add_rrset(store, domain, s))
5474564029fSflorian 			return 0;
5484564029fSflorian 	}
5494564029fSflorian 	return 1;
5504564029fSflorian }
5514564029fSflorian 
5524564029fSflorian /* check the difference between the domain and RRs from spool */
process_diff_domain(FILE * spool,struct ixfr_create * ixfrcr,struct ixfr_store * store,struct zone * zone,struct domain * domain)5534564029fSflorian static int process_diff_domain(FILE* spool, struct ixfr_create* ixfrcr,
5544564029fSflorian 	struct ixfr_store* store, struct zone* zone, struct domain* domain)
5554564029fSflorian {
5564564029fSflorian 	/* Read the RR types from spool. Mark off the ones seen,
5574564029fSflorian 	 * later, the notseen ones from the new zone are added RRsets.
5584564029fSflorian 	 * For the ones not in the new zone, they are deleted RRsets.
5594564029fSflorian 	 * If they exist in old and new, check for RR differences. */
5604564029fSflorian 	uint32_t spool_type_count, i;
5614564029fSflorian 	uint16_t marktypes[65536];
5624564029fSflorian 	size_t marktypes_used = 0;
5634564029fSflorian 	if(!read_spool_u32(spool, &spool_type_count)) {
5644564029fSflorian 		log_msg(LOG_ERR, "error reading file %s: %s",
5654564029fSflorian 			ixfrcr->file_name, strerror(errno));
5664564029fSflorian 		return 0;
5674564029fSflorian 	}
5683f21e8ccSflorian 	if(spool_type_count > sizeof(marktypes)) {
5693f21e8ccSflorian 		log_msg(LOG_ERR, "error reading file %s: spool type count "
5703f21e8ccSflorian 			"too large", ixfrcr->file_name);
5713f21e8ccSflorian 		return 0;
5723f21e8ccSflorian 	}
5734564029fSflorian 	for(i=0; i<spool_type_count; i++) {
5744564029fSflorian 		uint16_t tp, kl, rrcount;
5754564029fSflorian 		struct rrset* rrset;
5764564029fSflorian 		if(!read_spool_u16(spool, &tp) ||
5774564029fSflorian 		   !read_spool_u16(spool, &kl) ||
5784564029fSflorian 		   !read_spool_u16(spool, &rrcount)) {
5794564029fSflorian 			log_msg(LOG_ERR, "error reading file %s: %s",
5804564029fSflorian 				ixfrcr->file_name, strerror(errno));
5814564029fSflorian 			return 0;
5824564029fSflorian 		}
5833f21e8ccSflorian 		/* The rrcount is within limits of sizeof(marktypes), because
5843f21e8ccSflorian 		 * the uint16_t < 65536 */
5854564029fSflorian 		rrset = domain_find_rrset(domain, zone, tp);
5864564029fSflorian 		if(!rrset) {
5874564029fSflorian 			/* rrset in spool but not in new zone, deleted RRset */
5884564029fSflorian 			if(!process_spool_delrrset(spool, ixfrcr, store,
5894564029fSflorian 				(void*)dname_name(domain_dname(domain)),
5904564029fSflorian 				domain_dname(domain)->name_size, tp, kl,
5914564029fSflorian 				rrcount))
5924564029fSflorian 				return 0;
5934564029fSflorian 		} else {
5944564029fSflorian 			/* add to the marked types, this one is present in
5954564029fSflorian 			 * spool */
5964564029fSflorian 			marktypes[marktypes_used++] = tp;
5974564029fSflorian 			/* rrset in old and in new zone, diff the RRset */
5984564029fSflorian 			if(!process_diff_rrset(spool, ixfrcr, store, domain,
5994564029fSflorian 				tp, kl, rrcount, rrset))
6004564029fSflorian 				return 0;
6014564029fSflorian 		}
6024564029fSflorian 	}
6034564029fSflorian 	/* process markoff to see if new zone has RRsets not in spool,
6044564029fSflorian 	 * those are added RRsets. */
6054564029fSflorian 	if(!process_marktypes(store, zone, domain, marktypes, marktypes_used))
6064564029fSflorian 		return 0;
6074564029fSflorian 	return 1;
6084564029fSflorian }
6094564029fSflorian 
6104564029fSflorian /* add the RRs for the domain in new zone */
process_domain_add_RRs(struct ixfr_store * store,struct zone * zone,struct domain * domain)6114564029fSflorian static int process_domain_add_RRs(struct ixfr_store* store, struct zone* zone,
6124564029fSflorian 	struct domain* domain)
6134564029fSflorian {
6144564029fSflorian 	rrset_type* s;
6154564029fSflorian 	for(s=domain->rrsets; s; s=s->next) {
6164564029fSflorian 		if(s->zone != zone)
6174564029fSflorian 			continue;
6184564029fSflorian 		if(!process_add_rrset(store, domain, s))
6194564029fSflorian 			return 0;
6204564029fSflorian 	}
6214564029fSflorian 	return 1;
6224564029fSflorian }
6234564029fSflorian 
6244564029fSflorian /* del the RRs for the domain from the spool */
process_domain_del_RRs(struct ixfr_create * ixfrcr,struct ixfr_store * store,FILE * spool,uint8_t * dname,size_t dname_len)6254564029fSflorian static int process_domain_del_RRs(struct ixfr_create* ixfrcr,
6264564029fSflorian 	struct ixfr_store* store, FILE* spool, uint8_t* dname,
6274564029fSflorian 	size_t dname_len)
6284564029fSflorian {
6294564029fSflorian 	uint32_t spool_type_count, i;
6304564029fSflorian 	if(!read_spool_u32(spool, &spool_type_count)) {
6314564029fSflorian 		log_msg(LOG_ERR, "error reading file %s: %s",
6324564029fSflorian 			ixfrcr->file_name, strerror(errno));
6334564029fSflorian 		return 0;
6344564029fSflorian 	}
6353f21e8ccSflorian 	if(spool_type_count > 65536) {
6363f21e8ccSflorian 		log_msg(LOG_ERR, "error reading file %s: del RR spool type "
6373f21e8ccSflorian 			"count too large", ixfrcr->file_name);
6383f21e8ccSflorian 		return 0;
6393f21e8ccSflorian 	}
6404564029fSflorian 	for(i=0; i<spool_type_count; i++) {
6414564029fSflorian 		uint16_t tp, kl, rrcount;
6424564029fSflorian 		if(!read_spool_u16(spool, &tp) ||
6434564029fSflorian 		   !read_spool_u16(spool, &kl) ||
6444564029fSflorian 		   !read_spool_u16(spool, &rrcount)) {
6454564029fSflorian 			log_msg(LOG_ERR, "error reading file %s: %s",
6464564029fSflorian 				ixfrcr->file_name, strerror(errno));
6474564029fSflorian 			return 0;
6484564029fSflorian 		}
6493f21e8ccSflorian 		/* The rrcount is within reasonable limits, because
6503f21e8ccSflorian 		 * the uint16_t < 65536 */
6514564029fSflorian 		if(!process_spool_delrrset(spool, ixfrcr, store, dname,
6524564029fSflorian 			dname_len, tp, kl, rrcount))
6534564029fSflorian 			return 0;
6544564029fSflorian 	}
6554564029fSflorian 	return 1;
6564564029fSflorian }
6574564029fSflorian 
6584564029fSflorian /* init the spool dname iterator */
spool_dname_iter_init(struct spool_dname_iterator * iter,FILE * spool,char * file_name)6594564029fSflorian static void spool_dname_iter_init(struct spool_dname_iterator* iter,
6604564029fSflorian 	FILE* spool, char* file_name)
6614564029fSflorian {
6624564029fSflorian 	memset(iter, 0, sizeof(*iter));
6634564029fSflorian 	iter->spool = spool;
6644564029fSflorian 	iter->file_name = file_name;
6654564029fSflorian }
6664564029fSflorian 
6674564029fSflorian /* read the dname element into the buffer for the spool dname iterator */
spool_dname_iter_read(struct spool_dname_iterator * iter)6684564029fSflorian static int spool_dname_iter_read(struct spool_dname_iterator* iter)
6694564029fSflorian {
6704564029fSflorian 	if(!read_spool_dname(iter->spool, iter->dname, sizeof(iter->dname),
6714564029fSflorian 		&iter->dname_len)) {
6724564029fSflorian 		log_msg(LOG_ERR, "error reading file %s: %s",
6734564029fSflorian 			iter->file_name, strerror(errno));
6744564029fSflorian 		return 0;
6754564029fSflorian 	}
6764564029fSflorian 	return 1;
6774564029fSflorian }
6784564029fSflorian 
6794564029fSflorian /* get the next name to operate on, that is not processed yet, 0 on failure
6804564029fSflorian  * returns okay on endoffile, check with eof for that.
6814564029fSflorian  * when done with an element, set iter->is_processed on the element. */
spool_dname_iter_next(struct spool_dname_iterator * iter)6824564029fSflorian static int spool_dname_iter_next(struct spool_dname_iterator* iter)
6834564029fSflorian {
6844564029fSflorian 	if(iter->eof)
6854564029fSflorian 		return 1;
6864564029fSflorian 	if(!iter->read_first) {
6874564029fSflorian 		/* read the first one */
6884564029fSflorian 		if(!spool_dname_iter_read(iter))
6894564029fSflorian 			return 0;
6904564029fSflorian 		if(iter->dname_len == 0)
6914564029fSflorian 			iter->eof = 1;
6924564029fSflorian 		iter->read_first = 1;
6934564029fSflorian 		iter->is_processed = 0;
6944564029fSflorian 	}
6954564029fSflorian 	if(!iter->is_processed) {
6964564029fSflorian 		/* the current one needs processing */
6974564029fSflorian 		return 1;
6984564029fSflorian 	}
6994564029fSflorian 	/* read the next one */
7004564029fSflorian 	if(!spool_dname_iter_read(iter))
7014564029fSflorian 		return 0;
7024564029fSflorian 	if(iter->dname_len == 0)
7034564029fSflorian 		iter->eof = 1;
7044564029fSflorian 	iter->is_processed = 0;
7054564029fSflorian 	return 1;
7064564029fSflorian }
7074564029fSflorian 
7084564029fSflorian /* check if the ixfr is too large */
ixfr_create_too_large(struct ixfr_create * ixfrcr,struct ixfr_store * store)7094564029fSflorian static int ixfr_create_too_large(struct ixfr_create* ixfrcr,
7104564029fSflorian 	struct ixfr_store* store)
7114564029fSflorian {
7124564029fSflorian 	if(store->cancelled)
7134564029fSflorian 		return 1;
7144564029fSflorian 	if(ixfrcr->max_size != 0 &&
7154564029fSflorian 		ixfr_data_size(store->data) > ixfrcr->max_size) {
7164564029fSflorian 		if(ixfrcr->errorcmdline) {
7174564029fSflorian 			log_msg(LOG_ERR, "the ixfr for %s exceeds size %u, it is not created",
7184564029fSflorian 				wiredname2str(ixfrcr->zone_name),
7194564029fSflorian 				(unsigned)ixfrcr->max_size);
7204564029fSflorian 		} else {
7214564029fSflorian 			VERBOSITY(2, (LOG_INFO, "the ixfr for %s exceeds size %u, it is not created",
7224564029fSflorian 				wiredname2str(ixfrcr->zone_name),
7234564029fSflorian 				(unsigned)ixfrcr->max_size));
7244564029fSflorian 		}
7254564029fSflorian 		ixfr_store_cancel(store);
7264564029fSflorian 		return 1;
7274564029fSflorian 	}
7284564029fSflorian 	return 0;
7294564029fSflorian }
7304564029fSflorian 
7314564029fSflorian /* process the spool input before the domain */
process_spool_before_domain(FILE * spool,struct ixfr_create * ixfrcr,struct ixfr_store * store,struct domain * domain,struct spool_dname_iterator * iter,struct region * tmp_region)7324564029fSflorian static int process_spool_before_domain(FILE* spool, struct ixfr_create* ixfrcr,
7334564029fSflorian 	struct ixfr_store* store, struct domain* domain,
7344564029fSflorian 	struct spool_dname_iterator* iter, struct region* tmp_region)
7354564029fSflorian {
7364564029fSflorian 	const dname_type* dname;
7374564029fSflorian 	if(ixfr_create_too_large(ixfrcr, store))
7384564029fSflorian 		return 0;
7394564029fSflorian 	/* read the domains and rrsets before the domain and those are from
7404564029fSflorian 	 * the old zone. If the domain is equal, return to have that processed
7414564029fSflorian 	 * if we bypass, that means the domain does not exist, do that */
7424564029fSflorian 	while(!iter->eof) {
7434564029fSflorian 		if(!spool_dname_iter_next(iter))
7444564029fSflorian 			return 0;
7454564029fSflorian 		if(iter->eof)
7464564029fSflorian 			break;
7474564029fSflorian 		/* see if we are at, before or after the domain */
7484564029fSflorian 		dname = dname_make(tmp_region, iter->dname, 1);
7494564029fSflorian 		if(!dname) {
7504564029fSflorian 			log_msg(LOG_ERR, "error in dname in %s",
7514564029fSflorian 				iter->file_name);
7524564029fSflorian 			return 0;
7534564029fSflorian 		}
7544564029fSflorian 		if(dname_compare(dname, domain_dname(domain)) < 0) {
7554564029fSflorian 			/* the dname is smaller than the one from the zone.
7564564029fSflorian 			 * it must be deleted, process it */
7574564029fSflorian 			if(!process_domain_del_RRs(ixfrcr, store, spool,
7584564029fSflorian 				iter->dname, iter->dname_len))
7594564029fSflorian 				return 0;
7604564029fSflorian 			iter->is_processed = 1;
7614564029fSflorian 		} else {
7624564029fSflorian 			/* we are at or after the domain we are looking for,
7634564029fSflorian 			 * done here */
7644564029fSflorian 			return 1;
7654564029fSflorian 		}
7664564029fSflorian 		if(ixfr_create_too_large(ixfrcr, store))
7674564029fSflorian 			return 0;
7684564029fSflorian 	}
7694564029fSflorian 	/* no more domains on spool, done here */
7704564029fSflorian 	return 1;
7714564029fSflorian }
7724564029fSflorian 
7734564029fSflorian /* process the spool input for the domain */
process_spool_for_domain(FILE * spool,struct ixfr_create * ixfrcr,struct ixfr_store * store,struct zone * zone,struct domain * domain,struct spool_dname_iterator * iter,struct region * tmp_region)7744564029fSflorian static int process_spool_for_domain(FILE* spool, struct ixfr_create* ixfrcr,
7754564029fSflorian 	struct ixfr_store* store, struct zone* zone, struct domain* domain,
7764564029fSflorian 	struct spool_dname_iterator* iter, struct region* tmp_region)
7774564029fSflorian {
7784564029fSflorian 	/* process all the spool that is not the domain, that is before the
7794564029fSflorian 	 * domain in the new zone */
7804564029fSflorian 	if(!process_spool_before_domain(spool, ixfrcr, store, domain, iter,
7814564029fSflorian 		tmp_region))
7824564029fSflorian 		return 0;
7834564029fSflorian 
7844564029fSflorian 	if(ixfr_create_too_large(ixfrcr, store))
7854564029fSflorian 		return 0;
7864564029fSflorian 	/* are we at the correct domain now? */
7874564029fSflorian 	if(iter->eof || iter->dname_len != domain_dname(domain)->name_size ||
7884564029fSflorian 		memcmp(iter->dname, dname_name(domain_dname(domain)),
7894564029fSflorian 			iter->dname_len) != 0) {
7904564029fSflorian 		/* the domain from the new zone is not present in the old zone,
7914564029fSflorian 		 * the content is in the added RRs set */
7924564029fSflorian 		if(!process_domain_add_RRs(store, zone, domain))
7934564029fSflorian 			return 0;
7944564029fSflorian 		return 1;
7954564029fSflorian 	}
7964564029fSflorian 
7974564029fSflorian 	/* process the domain */
7984564029fSflorian 	/* the domain exists both in the old and new zone,
7994564029fSflorian 	 * check for RR differences */
8004564029fSflorian 	if(!process_diff_domain(spool, ixfrcr, store, zone, domain))
8014564029fSflorian 		return 0;
8024564029fSflorian 	iter->is_processed = 1;
8034564029fSflorian 
8044564029fSflorian 	return 1;
8054564029fSflorian }
8064564029fSflorian 
8074564029fSflorian /* process remaining spool items */
process_spool_remaining(FILE * spool,struct ixfr_create * ixfrcr,struct ixfr_store * store,struct spool_dname_iterator * iter)8084564029fSflorian static int process_spool_remaining(FILE* spool, struct ixfr_create* ixfrcr,
8094564029fSflorian 	struct ixfr_store* store, struct spool_dname_iterator* iter)
8104564029fSflorian {
8114564029fSflorian 	/* the remaining domain names in the spool file, that is after
8124564029fSflorian 	 * the last domain in the new zone. */
8134564029fSflorian 	if(ixfr_create_too_large(ixfrcr, store))
8144564029fSflorian 		return 0;
8154564029fSflorian 	while(!iter->eof) {
8164564029fSflorian 		if(!spool_dname_iter_next(iter))
8174564029fSflorian 			return 0;
8184564029fSflorian 		if(iter->eof)
8194564029fSflorian 			break;
8204564029fSflorian 		/* the domain only exists in the spool, the old zone,
8214564029fSflorian 		 * and not in the new zone. That would be domains
8224564029fSflorian 		 * after the new zone domains, or there are no new
8234564029fSflorian 		 * zone domains */
8244564029fSflorian 		if(!process_domain_del_RRs(ixfrcr, store, spool, iter->dname,
8254564029fSflorian 			iter->dname_len))
8264564029fSflorian 			return 0;
8274564029fSflorian 		iter->is_processed = 1;
8284564029fSflorian 		if(ixfr_create_too_large(ixfrcr, store))
8294564029fSflorian 			return 0;
8304564029fSflorian 	}
8314564029fSflorian 	return 1;
8324564029fSflorian }
8334564029fSflorian 
8344564029fSflorian /* walk through the zone and find the differences */
ixfr_create_walk_zone(FILE * spool,struct ixfr_create * ixfrcr,struct ixfr_store * store,struct zone * zone)8354564029fSflorian static int ixfr_create_walk_zone(FILE* spool, struct ixfr_create* ixfrcr,
8364564029fSflorian 	struct ixfr_store* store, struct zone* zone)
8374564029fSflorian {
8384564029fSflorian 	struct domain* domain;
8394564029fSflorian 	struct spool_dname_iterator iter;
8404564029fSflorian 	struct region* tmp_region;
8414564029fSflorian 	spool_dname_iter_init(&iter, spool, ixfrcr->file_name);
8424564029fSflorian 	tmp_region = region_create(xalloc, free);
8434564029fSflorian 	for(domain = zone->apex; domain && domain_is_subdomain(domain,
8444564029fSflorian 		zone->apex); domain = domain_next(domain)) {
8454564029fSflorian 		uint32_t count = domain_count_rrsets(domain, zone);
8464564029fSflorian 		if(count == 0)
8474564029fSflorian 			continue;
8484564029fSflorian 
8494564029fSflorian 		/* the domain is a domain in the new zone */
8504564029fSflorian 		if(!process_spool_for_domain(spool, ixfrcr, store, zone,
8514564029fSflorian 			domain, &iter, tmp_region)) {
8524564029fSflorian 			region_destroy(tmp_region);
8534564029fSflorian 			return 0;
8544564029fSflorian 		}
8554564029fSflorian 		region_free_all(tmp_region);
8564564029fSflorian 		if(ixfr_create_too_large(ixfrcr, store))
8574564029fSflorian 			return 0;
8584564029fSflorian 	}
8594564029fSflorian 	if(!process_spool_remaining(spool, ixfrcr, store, &iter)) {
8604564029fSflorian 		region_destroy(tmp_region);
8614564029fSflorian 		return 0;
8624564029fSflorian 	}
8634564029fSflorian 	region_destroy(tmp_region);
8644564029fSflorian 	return 1;
8654564029fSflorian }
8664564029fSflorian 
8674564029fSflorian /* see if the ixfr has already been created by reading the file header
8684564029fSflorian  * of the to-be-created file, if that file already exists */
ixfr_create_already_done_serial(struct zone * zone,const char * zfile,int checknew,uint32_t old_serial,uint32_t new_serial)8694564029fSflorian static int ixfr_create_already_done_serial(struct zone* zone,
8704564029fSflorian 	const char* zfile, int checknew, uint32_t old_serial,
8714564029fSflorian 	uint32_t new_serial)
8724564029fSflorian {
8734564029fSflorian 	uint32_t file_oldserial = 0, file_newserial = 0;
8744564029fSflorian 	size_t data_size = 0;
8754564029fSflorian 	if(!ixfr_read_file_header(zone->opts->name, zfile, 1, &file_oldserial,
8764564029fSflorian 		&file_newserial, &data_size, 0)) {
8774564029fSflorian 		/* could not read, so it was not done */
8784564029fSflorian 		return 0;
8794564029fSflorian 	}
8804564029fSflorian 	if(file_oldserial == old_serial &&
8814564029fSflorian 		(!checknew || file_newserial == new_serial)) {
8824564029fSflorian 		log_msg(LOG_INFO, "IXFR already exists in file %s.ixfr, nothing to do",
8834564029fSflorian 			zfile);
8844564029fSflorian 		return 1;
8854564029fSflorian 	}
8864564029fSflorian 	return 0;
8874564029fSflorian }
8884564029fSflorian 
8894564029fSflorian /* See the data size of the ixfr by reading the file header of the ixfr file */
ixfr_read_header_data_size(const char * zname,const char * zfile,int file_num,size_t * data_size)8904564029fSflorian static int ixfr_read_header_data_size(const char* zname,
8914564029fSflorian 	const char* zfile, int file_num, size_t* data_size)
8924564029fSflorian {
8934564029fSflorian 	uint32_t file_oldserial = 0, file_newserial = 0;
8944564029fSflorian 	if(!ixfr_read_file_header(zname, zfile, file_num, &file_oldserial,
8954564029fSflorian 		&file_newserial, data_size, 0)) {
8964564029fSflorian 		/* could not read */
8974564029fSflorian 		return 0;
8984564029fSflorian 	}
8994564029fSflorian 	return 1;
9004564029fSflorian }
9014564029fSflorian 
9024564029fSflorian /* see if the ixfr has already been created by reading the file header
9034564029fSflorian  * of the to-be-created file, if that file already exists */
ixfr_create_already_done(struct ixfr_create * ixfrcr,struct zone * zone,const char * zfile,int checknew)9044564029fSflorian static int ixfr_create_already_done(struct ixfr_create* ixfrcr,
9054564029fSflorian 	struct zone* zone, const char* zfile, int checknew)
9064564029fSflorian {
9074564029fSflorian 	return ixfr_create_already_done_serial(zone, zfile, checknew,
9084564029fSflorian 		ixfrcr->old_serial, ixfrcr->new_serial);
9094564029fSflorian }
9104564029fSflorian 
9114564029fSflorian /* store the new soa record for the ixfr */
ixfr_create_store_newsoa(struct ixfr_store * store,struct zone * zone)9124564029fSflorian static int ixfr_create_store_newsoa(struct ixfr_store* store,
9134564029fSflorian 	struct zone* zone)
9144564029fSflorian {
9154564029fSflorian 	if(!zone || !zone->soa_rrset) {
9164564029fSflorian 		log_msg(LOG_ERR, "error no SOA rrset");
9174564029fSflorian 		return 0;
9184564029fSflorian 	}
9194564029fSflorian 	if(zone->soa_rrset->rr_count == 0) {
9204564029fSflorian 		log_msg(LOG_ERR, "error empty SOA rrset");
9214564029fSflorian 		return 0;
9224564029fSflorian 	}
9234564029fSflorian 	if(!ixfr_store_add_newsoa_rdatas(store, domain_dname(zone->apex),
9244564029fSflorian 		zone->soa_rrset->rrs[0].type, zone->soa_rrset->rrs[0].klass,
9254564029fSflorian 		zone->soa_rrset->rrs[0].ttl, zone->soa_rrset->rrs[0].rdatas,
9264564029fSflorian 		zone->soa_rrset->rrs[0].rdata_count)) {
9274564029fSflorian 		log_msg(LOG_ERR, "out of memory");
9284564029fSflorian 		return 0;
9294564029fSflorian 	}
9304564029fSflorian 	return 1;
9314564029fSflorian }
9324564029fSflorian 
9334564029fSflorian /* initialise ixfr_create perform, open spool, read header, get serial */
ixfr_perform_init(struct ixfr_create * ixfrcr,struct zone * zone,struct ixfr_store * store_mem,struct ixfr_store ** store,FILE ** spool)9344564029fSflorian static int ixfr_perform_init(struct ixfr_create* ixfrcr, struct zone* zone,
9354564029fSflorian 	struct ixfr_store* store_mem, struct ixfr_store** store, FILE** spool)
9364564029fSflorian {
9374564029fSflorian 	*spool = fopen(ixfrcr->file_name, "r");
9384564029fSflorian 	if(!*spool) {
9394564029fSflorian 		log_msg(LOG_ERR, "could not open %s for reading: %s",
9404564029fSflorian 			ixfrcr->file_name, strerror(errno));
9414564029fSflorian 		return 0;
9424564029fSflorian 	}
9434564029fSflorian 	if(!read_spool_header(*spool, ixfrcr)) {
9444564029fSflorian 		fclose(*spool);
9454564029fSflorian 		return 0;
9464564029fSflorian 	}
9474564029fSflorian 	ixfrcr->new_serial = zone_get_current_serial(zone);
948*b71395eaSflorian 	*store = ixfr_store_start(zone, store_mem);
9494564029fSflorian 	if(!ixfr_create_store_newsoa(*store, zone)) {
9504564029fSflorian 		fclose(*spool);
9514564029fSflorian 		ixfr_store_free(*store);
9524564029fSflorian 		return 0;
9534564029fSflorian 	}
9544564029fSflorian 	return 1;
9554564029fSflorian }
9564564029fSflorian 
9574564029fSflorian /* rename the other ixfr files */
ixfr_create_rename_and_delete_files(const char * zname,const char * zoptsname,const char * zfile,uint32_t ixfr_number,size_t ixfr_size,size_t cur_data_size)9584564029fSflorian static int ixfr_create_rename_and_delete_files(const char* zname,
9594564029fSflorian 	const char* zoptsname, const char* zfile, uint32_t ixfr_number,
9604564029fSflorian 	size_t ixfr_size, size_t cur_data_size)
9614564029fSflorian {
9624564029fSflorian 	size_t size_in_use = cur_data_size;
9634564029fSflorian 	int dest_nr_files = (int)ixfr_number, maxsizehit = 0;
9644564029fSflorian 	int num = 1;
9654564029fSflorian 	while(ixfr_file_exists(zfile, num)) {
9664564029fSflorian 		size_t fsize = 0;
9674564029fSflorian 		if(!maxsizehit) {
9684564029fSflorian 			if(!ixfr_read_header_data_size(zoptsname, zfile, num,
9694564029fSflorian 				&fsize) || size_in_use + fsize > ixfr_size) {
9704564029fSflorian 				/* no more than this because of storage size */
9714564029fSflorian 				dest_nr_files = num;
9724564029fSflorian 				maxsizehit = 1;
9734564029fSflorian 			}
9744564029fSflorian 			size_in_use += fsize;
9754564029fSflorian 		}
9764564029fSflorian 		num++;
9774564029fSflorian 	}
9784564029fSflorian 	num--;
9794564029fSflorian 	/* num is now the number of ixfr files that exist */
9804564029fSflorian 	while(num > 0) {
9814564029fSflorian 		if(num+1 > dest_nr_files) {
9824564029fSflorian 			(void)ixfr_unlink_it(zname, zfile, num, 0);
9834564029fSflorian 		} else {
9844564029fSflorian 			if(!ixfr_rename_it(zname, zfile, num, 0, num+1, 0))
9854564029fSflorian 				return 0;
9864564029fSflorian 		}
9874564029fSflorian 		num--;
9884564029fSflorian 	}
9894564029fSflorian 	return 1;
9904564029fSflorian }
9914564029fSflorian 
9924564029fSflorian /* finish up ixfr create processing */
ixfr_create_finishup(struct ixfr_create * ixfrcr,struct ixfr_store * store,struct zone * zone,int append_mem,struct nsd * nsd,const char * zfile,uint32_t ixfr_number)9934564029fSflorian static void ixfr_create_finishup(struct ixfr_create* ixfrcr,
9944564029fSflorian 	struct ixfr_store* store, struct zone* zone, int append_mem,
9954564029fSflorian 	struct nsd* nsd, const char* zfile, uint32_t ixfr_number)
9964564029fSflorian {
9974564029fSflorian 	char log_buf[1024], nowstr[128];
9984564029fSflorian 	/* create the log message */
9994564029fSflorian 	time_t now = time(NULL);
10004564029fSflorian 	if(store->cancelled || ixfr_create_too_large(ixfrcr, store)) {
10014564029fSflorian 		/* remove unneeded files.
10024564029fSflorian 		 * since this ixfr cannot be created the others are useless. */
10034564029fSflorian 		ixfr_delete_superfluous_files(zone, zfile, 0);
10044564029fSflorian 		return;
10054564029fSflorian 	}
10064564029fSflorian 	snprintf(nowstr, sizeof(nowstr), "%s", ctime(&now));
10074564029fSflorian 	if(strchr(nowstr, '\n'))
10084564029fSflorian 		*strchr(nowstr, '\n') = 0;
10094564029fSflorian 	snprintf(log_buf, sizeof(log_buf),
10104564029fSflorian 		"IXFR created by NSD %s for %s %u to %u of %u bytes at time %s",
10114564029fSflorian 		PACKAGE_VERSION, wiredname2str(ixfrcr->zone_name),
10124564029fSflorian 		(unsigned)ixfrcr->old_serial, (unsigned)ixfrcr->new_serial,
10134564029fSflorian 		(unsigned)ixfr_data_size(store->data), nowstr);
10144564029fSflorian 	store->data->log_str = strdup(log_buf);
10154564029fSflorian 	if(!store->data->log_str) {
10164564029fSflorian 		log_msg(LOG_ERR, "out of memory");
10174564029fSflorian 		ixfr_store_free(store);
10184564029fSflorian 		return;
10194564029fSflorian 	}
10204564029fSflorian 	if(!ixfr_create_rename_and_delete_files(
10214564029fSflorian 		wiredname2str(ixfrcr->zone_name), zone->opts->name, zfile,
10224564029fSflorian 		ixfr_number, ixfrcr->max_size, ixfr_data_size(store->data))) {
10234564029fSflorian 		log_msg(LOG_ERR, "could not rename other ixfr files");
10244564029fSflorian 		ixfr_store_free(store);
10254564029fSflorian 		return;
10264564029fSflorian 	}
10274564029fSflorian 	if(!ixfr_write_file(zone, store->data, zfile, 1)) {
10284564029fSflorian 		log_msg(LOG_ERR, "could not write to file");
10294564029fSflorian 		ixfr_store_free(store);
10304564029fSflorian 		return;
10314564029fSflorian 	}
10324564029fSflorian 	if(append_mem) {
10334564029fSflorian 		ixfr_store_finish(store, nsd, log_buf);
10344564029fSflorian 	}
10354564029fSflorian }
10364564029fSflorian 
ixfr_readup_exist(struct zone * zone,struct nsd * nsd,const char * zfile)10374564029fSflorian void ixfr_readup_exist(struct zone* zone, struct nsd* nsd,
10384564029fSflorian 	const char* zfile)
10394564029fSflorian {
10404564029fSflorian 	/* the .ixfr file already exists with the correct serial numbers
10414564029fSflorian 	 * on the disk. Read up the ixfr files from the drive and put them
10424564029fSflorian 	 * in memory. To match the zone that has just been read.
10434564029fSflorian 	 * We can skip ixfr creation, and read up the files from the drive.
10444564029fSflorian 	 * If the files on the drive are consistent, we end up with exactly
10454564029fSflorian 	 * those ixfrs and that zone in memory.
10464564029fSflorian 	 * Presumably, the user has used nsd-checkzone to create an IXFR
10474564029fSflorian 	 * file and has put a new zone file, so we read up the data that
10484564029fSflorian 	 * we should have now.
10494564029fSflorian 	 * This also takes into account the config on number and size. */
10504564029fSflorian 	ixfr_read_from_file(nsd, zone, zfile);
10514564029fSflorian }
10524564029fSflorian 
ixfr_create_perform(struct ixfr_create * ixfrcr,struct zone * zone,int append_mem,struct nsd * nsd,const char * zfile,uint32_t ixfr_number)10534564029fSflorian int ixfr_create_perform(struct ixfr_create* ixfrcr, struct zone* zone,
10544564029fSflorian 	int append_mem, struct nsd* nsd, const char* zfile,
10554564029fSflorian 	uint32_t ixfr_number)
10564564029fSflorian {
10574564029fSflorian 	struct ixfr_store store_mem, *store;
10584564029fSflorian 	FILE* spool;
10594564029fSflorian 	if(!ixfr_perform_init(ixfrcr, zone, &store_mem, &store, &spool)) {
10604564029fSflorian 		(void)unlink(ixfrcr->file_name);
10614564029fSflorian 		return 0;
10624564029fSflorian 	}
10634564029fSflorian 	if(ixfrcr->new_serial == ixfrcr->old_serial ||
10644564029fSflorian 		compare_serial(ixfrcr->new_serial, ixfrcr->old_serial)<0) {
10654564029fSflorian 		log_msg(LOG_ERR, "zone %s ixfr could not be created because the serial is the same or moves backwards, from %u to %u",
10664564029fSflorian 			wiredname2str(ixfrcr->zone_name),
10674564029fSflorian 			(unsigned)ixfrcr->old_serial,
10684564029fSflorian 			(unsigned)ixfrcr->new_serial);
10694564029fSflorian 		ixfr_store_cancel(store);
10704564029fSflorian 		fclose(spool);
10714564029fSflorian 		ixfr_store_free(store);
10724564029fSflorian 		(void)unlink(ixfrcr->file_name);
10734564029fSflorian 		ixfr_delete_superfluous_files(zone, zfile, 0);
10744564029fSflorian 		if(append_mem)
10754564029fSflorian 			ixfr_store_delixfrs(zone);
10764564029fSflorian 		return 0;
10774564029fSflorian 	}
10784564029fSflorian 	if(ixfr_create_already_done(ixfrcr, zone, zfile, 1)) {
10794564029fSflorian 		ixfr_store_cancel(store);
10804564029fSflorian 		fclose(spool);
10814564029fSflorian 		ixfr_store_free(store);
10824564029fSflorian 		(void)unlink(ixfrcr->file_name);
10834564029fSflorian 		if(append_mem) {
10844564029fSflorian 			ixfr_readup_exist(zone, nsd, zfile);
10854564029fSflorian 		}
10864564029fSflorian 		return 0;
10874564029fSflorian 	}
10884564029fSflorian 
10894564029fSflorian 	if(!ixfr_create_walk_zone(spool, ixfrcr, store, zone)) {
10904564029fSflorian 		fclose(spool);
10914564029fSflorian 		ixfr_store_free(store);
10924564029fSflorian 		(void)unlink(ixfrcr->file_name);
10934564029fSflorian 		ixfr_delete_superfluous_files(zone, zfile, 0);
10944564029fSflorian 		return 0;
10954564029fSflorian 	}
10964564029fSflorian 	if(store->data && !store->data->oldsoa) {
10974564029fSflorian 		log_msg(LOG_ERR, "error spool file did not contain a SOA record");
10984564029fSflorian 		fclose(spool);
10994564029fSflorian 		ixfr_store_free(store);
11004564029fSflorian 		(void)unlink(ixfrcr->file_name);
11014564029fSflorian 		return 0;
11024564029fSflorian 	}
11034564029fSflorian 	if(!store->cancelled)
11044564029fSflorian 		ixfr_store_finish_data(store);
11054564029fSflorian 	fclose(spool);
11064564029fSflorian 	(void)unlink(ixfrcr->file_name);
11074564029fSflorian 
11084564029fSflorian 	ixfr_create_finishup(ixfrcr, store, zone, append_mem, nsd, zfile,
11094564029fSflorian 		ixfr_number);
11104564029fSflorian 	return 1;
11114564029fSflorian }
11124564029fSflorian 
ixfr_create_cancel(struct ixfr_create * ixfrcr)11134564029fSflorian void ixfr_create_cancel(struct ixfr_create* ixfrcr)
11144564029fSflorian {
11154564029fSflorian 	if(!ixfrcr)
11164564029fSflorian 		return;
11174564029fSflorian 	(void)unlink(ixfrcr->file_name);
11184564029fSflorian 	ixfr_create_free(ixfrcr);
11194564029fSflorian }
11204564029fSflorian 
ixfr_create_from_difference(struct zone * zone,const char * zfile,int * ixfr_create_already_done_flag)11214564029fSflorian int ixfr_create_from_difference(struct zone* zone, const char* zfile,
11224564029fSflorian 	int* ixfr_create_already_done_flag)
11234564029fSflorian {
11244564029fSflorian 	uint32_t old_serial;
11254564029fSflorian 	*ixfr_create_already_done_flag = 0;
11264564029fSflorian 	/* only if the zone is ixfr enabled */
11274564029fSflorian 	if(!zone_is_ixfr_enabled(zone))
11284564029fSflorian 		return 0;
11294564029fSflorian 	/* only if ixfr create is enabled */
11304564029fSflorian 	if(!zone->opts->pattern->create_ixfr)
11314564029fSflorian 		return 0;
11324564029fSflorian 	/* only if there is a zone in memory to compare with */
11333f21e8ccSflorian 	if(!zone->soa_rrset || !zone->apex)
11344564029fSflorian 		return 0;
11354564029fSflorian 
11364564029fSflorian 	old_serial = zone_get_current_serial(zone);
11374564029fSflorian 	if(ixfr_create_already_done_serial(zone, zfile, 0, old_serial, 0)) {
11384564029fSflorian 		*ixfr_create_already_done_flag = 1;
11394564029fSflorian 		return 0;
11404564029fSflorian 	}
11414564029fSflorian 
11424564029fSflorian 	return 1;
11434564029fSflorian }
1144