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