1/*
2 * difffile.c - DIFF file handling source code. Read and write diff files.
3 *
4 * Copyright (c) 2001-2006, NLnet Labs. All rights reserved.
5 *
6 * See LICENSE for the license.
7 *
8 */
9
10#include "config.h"
11#include <assert.h>
12#include <string.h>
13#include <unistd.h>
14#include <stdlib.h>
15#include <errno.h>
16#include "difffile.h"
17#include "xfrd-disk.h"
18#include "util.h"
19#include "packet.h"
20#include "rdata.h"
21#include "udb.h"
22#include "nsec3.h"
23#include "nsd.h"
24#include "rrl.h"
25#include "ixfr.h"
26#include "zonec.h"
27#include "xfrd-catalog-zones.h"
28
29static int
30write_64(FILE *out, uint64_t val)
31{
32	return write_data(out, &val, sizeof(val));
33}
34
35static int
36write_32(FILE *out, uint32_t val)
37{
38	val = htonl(val);
39	return write_data(out, &val, sizeof(val));
40}
41
42static int
43write_8(FILE *out, uint8_t val)
44{
45	return write_data(out, &val, sizeof(val));
46}
47
48static int
49write_str(FILE *out, const char* str)
50{
51	uint32_t len = strlen(str);
52	if(!write_32(out, len))
53		return 0;
54	return write_data(out, str, len);
55}
56
57void
58diff_write_packet(const char* zone, const char* pat, uint32_t old_serial,
59	uint32_t new_serial, uint32_t seq_nr, uint8_t* data, size_t len,
60	struct nsd* nsd, uint64_t filenumber)
61{
62	FILE* df = xfrd_open_xfrfile(nsd, filenumber, seq_nr?"a":"w");
63	if(!df) {
64		log_msg(LOG_ERR, "could not open transfer %s file %lld: %s",
65			zone, (long long)filenumber, strerror(errno));
66		return;
67	}
68
69	/* if first part, first write the header */
70	if(seq_nr == 0) {
71		struct timeval tv;
72		if (gettimeofday(&tv, NULL) != 0) {
73			log_msg(LOG_ERR, "could not get timestamp for %s: %s",
74				zone, strerror(errno));
75		}
76		if(!write_32(df, DIFF_PART_XFRF) ||
77			!write_8(df, 0) /* notcommitted(yet) */ ||
78			!write_32(df, 0) /* numberofparts when done */ ||
79			!write_64(df, (uint64_t) tv.tv_sec) ||
80			!write_32(df, (uint32_t) tv.tv_usec) ||
81			!write_32(df, old_serial) ||
82			!write_32(df, new_serial) ||
83			!write_64(df, (uint64_t) tv.tv_sec) ||
84			!write_32(df, (uint32_t) tv.tv_usec) ||
85			!write_str(df, zone) ||
86			!write_str(df, pat)) {
87			log_msg(LOG_ERR, "could not write transfer %s file %lld: %s",
88				zone, (long long)filenumber, strerror(errno));
89			fclose(df);
90			return;
91		}
92	}
93
94	if(!write_32(df, DIFF_PART_XXFR) ||
95		!write_32(df, len) ||
96		!write_data(df, data, len) ||
97		!write_32(df, len))
98	{
99		log_msg(LOG_ERR, "could not write transfer %s file %lld: %s",
100			zone, (long long)filenumber, strerror(errno));
101	}
102	fclose(df);
103}
104
105void
106diff_write_commit(const char* zone, uint32_t old_serial, uint32_t new_serial,
107	uint32_t num_parts, uint8_t commit, const char* log_str,
108	struct nsd* nsd, uint64_t filenumber)
109{
110	struct timeval tv;
111	FILE* df;
112
113	if (gettimeofday(&tv, NULL) != 0) {
114		log_msg(LOG_ERR, "could not set timestamp for %s: %s",
115			zone, strerror(errno));
116	}
117
118	/* overwrite the first part of the file with 'committed = 1',
119	 * as well as the end_time and number of parts.
120	 * also write old_serial and new_serial, so that a bad file mixup
121	 * will result in unusable serial numbers. */
122
123	df = xfrd_open_xfrfile(nsd, filenumber, "r+");
124	if(!df) {
125		log_msg(LOG_ERR, "could not open transfer %s file %lld: %s",
126			zone, (long long)filenumber, strerror(errno));
127		return;
128	}
129	if(!write_32(df, DIFF_PART_XFRF) ||
130		!write_8(df, commit) /* committed */ ||
131		!write_32(df, num_parts) ||
132		!write_64(df, (uint64_t) tv.tv_sec) ||
133		!write_32(df, (uint32_t) tv.tv_usec) ||
134		!write_32(df, old_serial) ||
135		!write_32(df, new_serial))
136	{
137		log_msg(LOG_ERR, "could not write transfer %s file %lld: %s",
138			zone, (long long)filenumber, strerror(errno));
139		fclose(df);
140		return;
141	}
142
143	/* append the log_str to the end of the file */
144	if(fseek(df, 0, SEEK_END) == -1) {
145		log_msg(LOG_ERR, "could not fseek transfer %s file %lld: %s",
146			zone, (long long)filenumber, strerror(errno));
147		fclose(df);
148		return;
149	}
150	if(!write_str(df, log_str)) {
151		log_msg(LOG_ERR, "could not write transfer %s file %lld: %s",
152			zone, (long long)filenumber, strerror(errno));
153		fclose(df);
154		return;
155
156	}
157	fflush(df);
158	fclose(df);
159}
160
161void
162diff_update_commit(
163	const char* zone, uint8_t commit, struct nsd* nsd, uint64_t filenumber)
164{
165	FILE *df;
166
167	assert(zone != NULL);
168	assert(nsd != NULL);
169	assert(commit == DIFF_NOT_COMMITTED ||
170	       commit == DIFF_COMMITTED ||
171	       commit == DIFF_CORRUPT ||
172	       commit == DIFF_INCONSISTENT ||
173	       commit == DIFF_VERIFIED);
174
175	df = xfrd_open_xfrfile(nsd, filenumber, "r+");
176	if(!df) {
177		log_msg(LOG_ERR, "could not open transfer %s file %lld: %s",
178			zone, (long long)filenumber, strerror(errno));
179		return;
180	}
181	if(!write_32(df, DIFF_PART_XFRF) || !write_8(df, commit)) {
182		log_msg(LOG_ERR, "could not write transfer %s file %lld: %s",
183			zone, (long long)filenumber, strerror(errno));
184		fclose(df);
185		return;
186	}
187	fflush(df);
188	fclose(df);
189}
190
191int
192diff_read_64(FILE *in, uint64_t* result)
193{
194	if (fread(result, sizeof(*result), 1, in) == 1) {
195		return 1;
196	} else {
197		return 0;
198	}
199}
200
201int
202diff_read_32(FILE *in, uint32_t* result)
203{
204	if (fread(result, sizeof(*result), 1, in) == 1) {
205		*result = ntohl(*result);
206		return 1;
207	} else {
208		return 0;
209	}
210}
211
212int
213diff_read_8(FILE *in, uint8_t* result)
214{
215	if (fread(result, sizeof(*result), 1, in) == 1) {
216		return 1;
217	} else {
218		return 0;
219	}
220}
221
222int
223diff_read_str(FILE* in, char* buf, size_t len)
224{
225	uint32_t disklen;
226	if(!diff_read_32(in, &disklen))
227		return 0;
228	if(disklen >= len)
229		return 0;
230	if(fread(buf, disklen, 1, in) != 1)
231		return 0;
232	buf[disklen] = 0;
233	return 1;
234}
235
236static void
237add_rdata_to_recyclebin(namedb_type* db, rr_type* rr)
238{
239	/* add rdatas to recycle bin. */
240	size_t i;
241	for(i=0; i<rr->rdata_count; i++)
242	{
243		if(!rdata_atom_is_domain(rr->type, i))
244			region_recycle(db->region, rr->rdatas[i].data,
245				rdata_atom_size(rr->rdatas[i])
246				+ sizeof(uint16_t));
247	}
248	region_recycle(db->region, rr->rdatas,
249		sizeof(rdata_atom_type)*rr->rdata_count);
250}
251
252/* this routine determines if below a domain there exist names with
253 * data (is_existing) or no names below the domain have data.
254 */
255static int
256has_data_below(domain_type* top)
257{
258	domain_type* d = top;
259	assert(d != NULL);
260	/* in the canonical ordering subdomains are after this name */
261	d = domain_next(d);
262	while(d != NULL && domain_is_subdomain(d, top)) {
263		if(d->is_existing)
264			return 1;
265		d = domain_next(d);
266	}
267	return 0;
268}
269
270/** check if domain with 0 rrsets has become empty (nonexist) */
271static domain_type*
272rrset_zero_nonexist_check(domain_type* domain, domain_type* ce)
273{
274	/* is the node now an empty node (completely deleted) */
275	if(domain->rrsets == 0) {
276		/* if there is no data below it, it becomes non existing.
277		   also empty nonterminals above it become nonexisting */
278		/* check for data below this node. */
279		if(!has_data_below(domain)) {
280			/* nonexist this domain and all parent empty nonterminals */
281			domain_type* p = domain;
282			while(p != NULL && p->rrsets == 0) {
283				if(p == ce || has_data_below(p))
284					return p;
285				p->is_existing = 0;
286				/* fixup wildcard child of parent */
287				if(p->parent &&
288					p->parent->wildcard_child_closest_match == p)
289					p->parent->wildcard_child_closest_match = domain_previous_existing_child(p);
290				p = p->parent;
291			}
292		}
293	}
294	return NULL;
295}
296
297/** remove rrset.  Adjusts zone params.  Does not remove domain */
298static void
299rrset_delete(namedb_type* db, domain_type* domain, rrset_type* rrset)
300{
301	int i;
302	/* find previous */
303	rrset_type** pp = &domain->rrsets;
304	while(*pp && *pp != rrset) {
305		pp = &( (*pp)->next );
306	}
307	if(!*pp) {
308		/* rrset does not exist for domain */
309		return;
310	}
311	*pp = rrset->next;
312
313	DEBUG(DEBUG_XFRD,2, (LOG_INFO, "delete rrset of %s type %s",
314		domain_to_string(domain),
315		rrtype_to_string(rrset_rrtype(rrset))));
316
317	/* is this a SOA rrset ? */
318	if(rrset->zone->soa_rrset == rrset) {
319		rrset->zone->soa_rrset = 0;
320	}
321	if(rrset->zone->ns_rrset == rrset) {
322		rrset->zone->ns_rrset = 0;
323	}
324	if(domain == rrset->zone->apex && rrset_rrtype(rrset) == TYPE_RRSIG) {
325		for (i = 0; i < rrset->rr_count; ++i) {
326			if(rr_rrsig_type_covered(&rrset->rrs[i])==TYPE_DNSKEY) {
327				rrset->zone->is_secure = 0;
328				break;
329			}
330		}
331	}
332	/* recycle the memory space of the rrset */
333	for (i = 0; i < rrset->rr_count; ++i)
334		add_rdata_to_recyclebin(db, &rrset->rrs[i]);
335	region_recycle(db->region, rrset->rrs,
336		sizeof(rr_type) * rrset->rr_count);
337	rrset->rr_count = 0;
338	region_recycle(db->region, rrset, sizeof(rrset_type));
339}
340
341static int
342rdatas_equal(rdata_atom_type *a, rdata_atom_type *b, int num, uint16_t type,
343	int* rdnum, char** reason)
344{
345	int k, start, end;
346	start = 0;
347	end = num;
348	/**
349	 * SOA RDATA comparisons in XFR are more lenient,
350	 * only serial rdata is checked.
351	 **/
352	if (type == TYPE_SOA) {
353		start = 2;
354		end = 3;
355	}
356	for(k = start; k < end; k++)
357	{
358		if(rdata_atom_is_domain(type, k)) {
359			if(dname_compare(domain_dname(a[k].domain),
360				domain_dname(b[k].domain))!=0) {
361				*rdnum = k;
362				*reason = "dname data";
363				return 0;
364			}
365		} else if(rdata_atom_is_literal_domain(type, k)) {
366			/* literal dname, but compare case insensitive */
367			if(a[k].data[0] != b[k].data[0]) {
368				*rdnum = k;
369				*reason = "literal dname len";
370				return 0; /* uncompressed len must be equal*/
371			}
372			if(!dname_equal_nocase((uint8_t*)(a[k].data+1),
373				(uint8_t*)(b[k].data+1), a[k].data[0])) {
374				*rdnum = k;
375				*reason = "literal dname data";
376				return 0;
377			}
378		} else {
379			/* check length */
380			if(a[k].data[0] != b[k].data[0]) {
381				*rdnum = k;
382				*reason = "rdata len";
383				return 0;
384			}
385			/* check data */
386			if(memcmp(a[k].data+1, b[k].data+1, a[k].data[0])!=0) {
387				*rdnum = k;
388				*reason = "rdata data";
389				return 0;
390			}
391		}
392	}
393	return 1;
394}
395
396static void
397debug_find_rr_num(rrset_type* rrset, uint16_t type, uint16_t klass,
398	rdata_atom_type *rdatas, ssize_t rdata_num)
399{
400	int i, rd;
401	char* reason = "";
402
403	for(i=0; i < rrset->rr_count; ++i) {
404		if (rrset->rrs[i].type != type) {
405			log_msg(LOG_WARNING, "diff: RR <%s, %s> does not match "
406				"RR num %d type %s",
407				dname_to_string(domain_dname(rrset->rrs[i].owner),0),
408				rrtype_to_string(type),	i,
409				rrtype_to_string(rrset->rrs[i].type));
410		}
411		if (rrset->rrs[i].klass != klass) {
412			log_msg(LOG_WARNING, "diff: RR <%s, %s> class %d "
413				"does not match RR num %d class %d",
414				dname_to_string(domain_dname(rrset->rrs[i].owner),0),
415				rrtype_to_string(type),
416				klass, i,
417				rrset->rrs[i].klass);
418		}
419		if (rrset->rrs[i].rdata_count != rdata_num) {
420			log_msg(LOG_WARNING, "diff: RR <%s, %s> rdlen %u "
421				"does not match RR num %d rdlen %d",
422				dname_to_string(domain_dname(rrset->rrs[i].owner),0),
423				rrtype_to_string(type),
424				(unsigned) rdata_num, i,
425				(unsigned) rrset->rrs[i].rdata_count);
426		}
427		if (!rdatas_equal(rdatas, rrset->rrs[i].rdatas, rdata_num, type,
428			&rd, &reason)) {
429			log_msg(LOG_WARNING, "diff: RR <%s, %s> rdata element "
430				"%d differs from RR num %d rdata (%s)",
431				dname_to_string(domain_dname(rrset->rrs[i].owner),0),
432				rrtype_to_string(type),
433				rd, i, reason);
434		}
435	}
436}
437
438static int
439find_rr_num(rrset_type* rrset, uint16_t type, uint16_t klass,
440	rdata_atom_type *rdatas, ssize_t rdata_num, int add)
441{
442	int i, rd;
443	char* reason;
444
445	for(i=0; i < rrset->rr_count; ++i) {
446		if(rrset->rrs[i].type == type &&
447		   rrset->rrs[i].klass == klass &&
448		   rrset->rrs[i].rdata_count == rdata_num &&
449		   rdatas_equal(rdatas, rrset->rrs[i].rdatas, rdata_num, type,
450			&rd, &reason))
451		{
452			return i;
453		}
454	}
455	/* this is odd. Log why rr cannot be found. */
456	if (!add) {
457		debug_find_rr_num(rrset, type, klass, rdatas, rdata_num);
458	}
459	return -1;
460}
461
462#ifdef NSEC3
463/* see if nsec3 deletion triggers need action */
464static void
465nsec3_delete_rr_trigger(namedb_type* db, rr_type* rr, zone_type* zone)
466{
467	/* the RR has not actually been deleted yet, so we can inspect it */
468	if(!zone->nsec3_param)
469		return;
470	/* see if the domain was an NSEC3-domain in the chain, but no longer */
471	if(rr->type == TYPE_NSEC3 && rr->owner->nsec3 &&
472		rr->owner->nsec3->nsec3_node.key &&
473		nsec3_rr_uses_params(rr, zone) &&
474		nsec3_in_chain_count(rr->owner, zone) <= 1) {
475		domain_type* prev = nsec3_chain_find_prev(zone, rr->owner);
476		/* remove from prehash because no longer an NSEC3 domain */
477		if(domain_is_prehash(db->domains, rr->owner))
478			prehash_del(db->domains, rr->owner);
479		/* fixup the last in the zone */
480		if(rr->owner == zone->nsec3_last)
481			zone->nsec3_last = prev;
482		/* unlink from the nsec3tree */
483		zone_del_domain_in_hash_tree(zone->nsec3tree,
484			&rr->owner->nsec3->nsec3_node);
485		/* add previous NSEC3 to the prehash list */
486		if(prev && prev != rr->owner)
487			prehash_add(db->domains, prev);
488		else	nsec3_clear_precompile(db, zone);
489		/* this domain becomes ordinary data domain: done later */
490	}
491	/* see if the rr was NSEC3PARAM that we were using */
492	else if(rr->type == TYPE_NSEC3PARAM && rr == zone->nsec3_param) {
493		/* clear trees, wipe hashes, wipe precompile */
494		nsec3_clear_precompile(db, zone);
495		/* pick up new nsec3param (from udb, or avoid deleted rr) */
496		nsec3_find_zone_param(db, zone, rr, 0);
497		/* if no more NSEC3, done */
498		if(!zone->nsec3_param)
499			return;
500		nsec3_precompile_newparam(db, zone);
501	}
502}
503
504/* see if nsec3 prehash can be removed with new rrset content */
505static void
506nsec3_rrsets_changed_remove_prehash(domain_type* domain, zone_type* zone)
507{
508	/* deletion of rrset already done, we can check if conditions apply */
509	/* see if the domain is no longer precompiled */
510	/* it has a hash_node, but no longer fulfills conditions */
511	if(nsec3_domain_part_of_zone(domain, zone) && domain->nsec3 &&
512		domain->nsec3->hash_wc &&
513		domain->nsec3->hash_wc->hash.node.key &&
514		!nsec3_condition_hash(domain, zone)) {
515		/* remove precompile */
516		domain->nsec3->nsec3_cover = NULL;
517		domain->nsec3->nsec3_wcard_child_cover = NULL;
518		domain->nsec3->nsec3_is_exact = 0;
519		/* remove it from the hash tree */
520		zone_del_domain_in_hash_tree(zone->hashtree,
521			&domain->nsec3->hash_wc->hash.node);
522		zone_del_domain_in_hash_tree(zone->wchashtree,
523			&domain->nsec3->hash_wc->wc.node);
524	}
525	if(domain != zone->apex && domain->nsec3 &&
526		domain->nsec3->ds_parent_hash &&
527		domain->nsec3->ds_parent_hash->node.key &&
528		(!domain->parent || nsec3_domain_part_of_zone(domain->parent, zone)) &&
529		!nsec3_condition_dshash(domain, zone)) {
530		/* remove precompile */
531		domain->nsec3->nsec3_ds_parent_cover = NULL;
532		domain->nsec3->nsec3_ds_parent_is_exact = 0;
533		/* remove it from the hash tree */
534		zone_del_domain_in_hash_tree(zone->dshashtree,
535			&domain->nsec3->ds_parent_hash->node);
536	}
537}
538
539/* see if domain needs to get precompiled info */
540static void
541nsec3_rrsets_changed_add_prehash(namedb_type* db, domain_type* domain,
542	zone_type* zone)
543{
544	if(!zone->nsec3_param)
545		return;
546	if((!domain->nsec3 || !domain->nsec3->hash_wc
547	                   || !domain->nsec3->hash_wc->hash.node.key)
548		&& nsec3_condition_hash(domain, zone)) {
549		region_type* tmpregion = region_create(xalloc, free);
550		nsec3_precompile_domain(db, domain, zone, tmpregion);
551		region_destroy(tmpregion);
552	}
553	if((!domain->nsec3 || !domain->nsec3->ds_parent_hash
554	                   || !domain->nsec3->ds_parent_hash->node.key)
555		&& nsec3_condition_dshash(domain, zone)) {
556		nsec3_precompile_domain_ds(db, domain, zone);
557	}
558}
559
560/* see if nsec3 rrset-deletion triggers need action */
561static void
562nsec3_delete_rrset_trigger(namedb_type* db, domain_type* domain,
563	zone_type* zone, uint16_t type)
564{
565	if(!zone->nsec3_param)
566		return;
567	nsec3_rrsets_changed_remove_prehash(domain, zone);
568	/* for type nsec3, or a delegation, the domain may have become a
569	 * 'normal' domain with its remaining data now */
570	if(type == TYPE_NSEC3 || type == TYPE_NS || type == TYPE_DS)
571		nsec3_rrsets_changed_add_prehash(db, domain, zone);
572	/* for type DNAME or a delegation, obscured data may be revealed */
573	if(type == TYPE_NS || type == TYPE_DS || type == TYPE_DNAME) {
574		/* walk over subdomains and check them each */
575		domain_type *d;
576		for(d=domain_next(domain); d && domain_is_subdomain(d, domain);
577			d=domain_next(d)) {
578			nsec3_rrsets_changed_add_prehash(db, d, zone);
579		}
580	}
581}
582
583/* see if nsec3 addition triggers need action */
584static void
585nsec3_add_rr_trigger(namedb_type* db, rr_type* rr, zone_type* zone)
586{
587	/* the RR has been added in full, also to UDB (and thus NSEC3PARAM
588	 * in the udb has been adjusted) */
589	if(zone->nsec3_param && rr->type == TYPE_NSEC3 &&
590		(!rr->owner->nsec3 || !rr->owner->nsec3->nsec3_node.key)
591		&& nsec3_rr_uses_params(rr, zone)) {
592		if(!zone->nsec3_last) {
593			/* all nsec3s have previously been deleted, but
594			 * we have nsec3 parameters, set it up again from
595			 * being cleared. */
596			nsec3_precompile_newparam(db, zone);
597		}
598		/* added NSEC3 into the chain */
599		nsec3_precompile_nsec3rr(db, rr->owner, zone);
600		/* the domain has become an NSEC3-domain, if it was precompiled
601		 * previously, remove that, neatly done in routine above */
602		nsec3_rrsets_changed_remove_prehash(rr->owner, zone);
603		/* set this NSEC3 to prehash */
604		prehash_add(db->domains, rr->owner);
605	} else if(!zone->nsec3_param && rr->type == TYPE_NSEC3PARAM) {
606		/* see if this means NSEC3 chain can be used */
607		nsec3_find_zone_param(db, zone, NULL, 0);
608		if(!zone->nsec3_param)
609			return;
610		nsec3_zone_trees_create(db->region, zone);
611		nsec3_precompile_newparam(db, zone);
612	}
613}
614
615/* see if nsec3 rrset-addition triggers need action */
616static void
617nsec3_add_rrset_trigger(namedb_type* db, domain_type* domain, zone_type* zone,
618	uint16_t type)
619{
620	/* the rrset has been added so we can inspect it */
621	if(!zone->nsec3_param)
622		return;
623	/* because the rrset is added we can check conditions easily.
624	 * check if domain needs to become precompiled now */
625	nsec3_rrsets_changed_add_prehash(db, domain, zone);
626	/* if a delegation, it changes from normal name to unhashed referral */
627	if(type == TYPE_NS || type == TYPE_DS) {
628		nsec3_rrsets_changed_remove_prehash(domain, zone);
629	}
630	/* if delegation or DNAME added, then some RRs may get obscured */
631	if(type == TYPE_NS || type == TYPE_DS || type == TYPE_DNAME) {
632		/* walk over subdomains and check them each */
633		domain_type *d;
634		for(d=domain_next(domain); d && domain_is_subdomain(d, domain);
635			d=domain_next(d)) {
636			nsec3_rrsets_changed_remove_prehash(d, zone);
637		}
638	}
639}
640#endif /* NSEC3 */
641
642/* fixup usage lower for domain names in the rdata */
643static void
644rr_lower_usage(namedb_type* db, rr_type* rr)
645{
646	unsigned i;
647	for(i=0; i<rr->rdata_count; i++) {
648		if(rdata_atom_is_domain(rr->type, i)) {
649			assert(rdata_atom_domain(rr->rdatas[i])->usage > 0);
650			rdata_atom_domain(rr->rdatas[i])->usage --;
651			if(rdata_atom_domain(rr->rdatas[i])->usage == 0)
652				domain_table_deldomain(db,
653					rdata_atom_domain(rr->rdatas[i]));
654		}
655	}
656}
657
658static void
659rrset_lower_usage(namedb_type* db, rrset_type* rrset)
660{
661	unsigned i;
662	for(i=0; i<rrset->rr_count; i++)
663		rr_lower_usage(db, &rrset->rrs[i]);
664}
665
666int
667delete_RR(namedb_type* db, const dname_type* dname,
668	uint16_t type, uint16_t klass,
669	buffer_type* packet, size_t rdatalen, zone_type *zone,
670	region_type* temp_region, int* softfail)
671{
672	domain_type *domain;
673	rrset_type *rrset;
674	domain = domain_table_find(db->domains, dname);
675	if(!domain) {
676		log_msg(LOG_WARNING, "diff: domain %s does not exist",
677			dname_to_string(dname,0));
678		buffer_skip(packet, rdatalen);
679		*softfail = 1;
680		return 1; /* not fatal error */
681	}
682	rrset = domain_find_rrset(domain, zone, type);
683	if(!rrset) {
684		log_msg(LOG_WARNING, "diff: rrset %s does not exist",
685			dname_to_string(dname,0));
686		buffer_skip(packet, rdatalen);
687		*softfail = 1;
688		return 1; /* not fatal error */
689	} else {
690		/* find the RR in the rrset */
691		domain_table_type *temptable;
692		rdata_atom_type *rdatas;
693		ssize_t rdata_num;
694		int rrnum;
695		temptable = domain_table_create(temp_region);
696		/* This will ensure that the dnames in rdata are
697		 * normalized, conform RFC 4035, section 6.2
698		 */
699		rdata_num = rdata_wireformat_to_rdata_atoms(
700			temp_region, temptable, type, rdatalen, packet, &rdatas);
701		if(rdata_num == -1) {
702			log_msg(LOG_ERR, "diff: bad rdata for %s",
703				dname_to_string(dname,0));
704			return 0;
705		}
706		rrnum = find_rr_num(rrset, type, klass, rdatas, rdata_num, 0);
707		if(rrnum == -1 && type == TYPE_SOA && domain == zone->apex
708			&& rrset->rr_count != 0)
709			rrnum = 0; /* replace existing SOA if no match */
710		if(rrnum == -1) {
711			log_msg(LOG_WARNING, "diff: RR <%s, %s> does not exist",
712				dname_to_string(dname,0), rrtype_to_string(type));
713			*softfail = 1;
714			return 1; /* not fatal error */
715		}
716#ifdef NSEC3
717		/* process triggers for RR deletions */
718		nsec3_delete_rr_trigger(db, &rrset->rrs[rrnum], zone);
719#endif
720		/* lower usage (possibly deleting other domains, and thus
721		 * invalidating the current RR's domain pointers) */
722		rr_lower_usage(db, &rrset->rrs[rrnum]);
723		if(rrset->rr_count == 1) {
724			/* delete entire rrset */
725			rrset_delete(db, domain, rrset);
726			/* check if domain is now nonexisting (or parents) */
727			rrset_zero_nonexist_check(domain, NULL);
728#ifdef NSEC3
729			/* cleanup nsec3 */
730			nsec3_delete_rrset_trigger(db, domain, zone, type);
731#endif
732			/* see if the domain can be deleted (and inspect parents) */
733			domain_table_deldomain(db, domain);
734		} else {
735			/* swap out the bad RR and decrease the count */
736			rr_type* rrs_orig = rrset->rrs;
737			add_rdata_to_recyclebin(db, &rrset->rrs[rrnum]);
738			if(rrnum < rrset->rr_count-1)
739				rrset->rrs[rrnum] = rrset->rrs[rrset->rr_count-1];
740			memset(&rrset->rrs[rrset->rr_count-1], 0, sizeof(rr_type));
741			/* realloc the rrs array one smaller */
742			rrset->rrs = region_alloc_array_init(db->region, rrs_orig,
743				(rrset->rr_count-1), sizeof(rr_type));
744			if(!rrset->rrs) {
745				log_msg(LOG_ERR, "out of memory, %s:%d", __FILE__, __LINE__);
746				exit(1);
747			}
748			region_recycle(db->region, rrs_orig,
749				sizeof(rr_type) * rrset->rr_count);
750#ifdef NSEC3
751			if(type == TYPE_NSEC3PARAM && zone->nsec3_param) {
752				/* fixup nsec3_param pointer to same RR */
753				assert(zone->nsec3_param >= rrs_orig &&
754					zone->nsec3_param <=
755					rrs_orig+rrset->rr_count);
756				/* last moved to rrnum, others at same index*/
757				if(zone->nsec3_param == &rrs_orig[
758					rrset->rr_count-1])
759					zone->nsec3_param = &rrset->rrs[rrnum];
760				else
761					zone->nsec3_param =
762						(void*)zone->nsec3_param
763						-(void*)rrs_orig +
764						(void*)rrset->rrs;
765			}
766#endif /* NSEC3 */
767			rrset->rr_count --;
768#ifdef NSEC3
769			/* for type nsec3, the domain may have become a
770			 * 'normal' domain with its remaining data now */
771			if(type == TYPE_NSEC3)
772				nsec3_rrsets_changed_add_prehash(db, domain,
773					zone);
774#endif /* NSEC3 */
775		}
776	}
777	return 1;
778}
779
780int
781add_RR(namedb_type* db, const dname_type* dname,
782	uint16_t type, uint16_t klass, uint32_t ttl,
783	buffer_type* packet, size_t rdatalen, zone_type *zone,
784	int* softfail)
785{
786	domain_type* domain;
787	rrset_type* rrset;
788	rdata_atom_type *rdatas;
789	rr_type *rrs_old;
790	ssize_t rdata_num;
791	int rrnum;
792#ifdef NSEC3
793	int rrset_added = 0;
794#endif
795	domain = domain_table_find(db->domains, dname);
796	if(!domain) {
797		/* create the domain */
798		domain = domain_table_insert(db->domains, dname);
799	}
800	rrset = domain_find_rrset(domain, zone, type);
801	if(!rrset) {
802		/* create the rrset */
803		rrset = region_alloc(db->region, sizeof(rrset_type));
804		if(!rrset) {
805			log_msg(LOG_ERR, "out of memory, %s:%d", __FILE__, __LINE__);
806			exit(1);
807		}
808		rrset->zone = zone;
809		rrset->rrs = 0;
810		rrset->rr_count = 0;
811		domain_add_rrset(domain, rrset);
812#ifdef NSEC3
813		rrset_added = 1;
814#endif
815	}
816
817	/* dnames in rdata are normalized, conform RFC 4035,
818	 * Section 6.2
819	 */
820	rdata_num = rdata_wireformat_to_rdata_atoms(
821		db->region, db->domains, type, rdatalen, packet, &rdatas);
822	if(rdata_num == -1) {
823		log_msg(LOG_ERR, "diff: bad rdata for %s",
824			dname_to_string(dname,0));
825		return 0;
826	}
827	rrnum = find_rr_num(rrset, type, klass, rdatas, rdata_num, 1);
828	if(rrnum != -1) {
829		DEBUG(DEBUG_XFRD, 2, (LOG_ERR, "diff: RR <%s, %s> already exists",
830			dname_to_string(dname,0), rrtype_to_string(type)));
831		/* ignore already existing RR: lenient accepting of messages */
832		*softfail = 1;
833		return 1;
834	}
835	if(rrset->rr_count == 65535) {
836		log_msg(LOG_ERR, "diff: too many RRs at %s",
837			dname_to_string(dname,0));
838		return 0;
839	}
840
841	/* re-alloc the rrs and add the new */
842	rrs_old = rrset->rrs;
843	rrset->rrs = region_alloc_array(db->region,
844		(rrset->rr_count+1), sizeof(rr_type));
845	if(!rrset->rrs) {
846		log_msg(LOG_ERR, "out of memory, %s:%d", __FILE__, __LINE__);
847		exit(1);
848	}
849	if(rrs_old)
850		memcpy(rrset->rrs, rrs_old, rrset->rr_count * sizeof(rr_type));
851	region_recycle(db->region, rrs_old, sizeof(rr_type) * rrset->rr_count);
852	rrset->rr_count ++;
853
854	rrset->rrs[rrset->rr_count - 1].owner = domain;
855	rrset->rrs[rrset->rr_count - 1].rdatas = rdatas;
856	rrset->rrs[rrset->rr_count - 1].ttl = ttl;
857	rrset->rrs[rrset->rr_count - 1].type = type;
858	rrset->rrs[rrset->rr_count - 1].klass = klass;
859	rrset->rrs[rrset->rr_count - 1].rdata_count = rdata_num;
860
861	/* see if it is a SOA */
862	if(domain == zone->apex) {
863		apex_rrset_checks(db, rrset, domain);
864#ifdef NSEC3
865		if(type == TYPE_NSEC3PARAM && zone->nsec3_param) {
866			/* the pointer just changed, fix it up to point
867			 * to the same record */
868			assert(zone->nsec3_param >= rrs_old &&
869				zone->nsec3_param < rrs_old+rrset->rr_count);
870			/* in this order to make sure no overflow/underflow*/
871			zone->nsec3_param = (void*)zone->nsec3_param -
872				(void*)rrs_old + (void*)rrset->rrs;
873		}
874#endif /* NSEC3 */
875	}
876
877#ifdef NSEC3
878	if(rrset_added) {
879		domain_type* p = domain->parent;
880		nsec3_add_rrset_trigger(db, domain, zone, type);
881		/* go up and process (possibly created) empty nonterminals,
882		 * until we hit the apex or root */
883		while(p && p->rrsets == NULL && !p->is_apex) {
884			nsec3_rrsets_changed_add_prehash(db, p, zone);
885			p = p->parent;
886		}
887	}
888	nsec3_add_rr_trigger(db, &rrset->rrs[rrset->rr_count - 1], zone);
889#endif /* NSEC3 */
890	return 1;
891}
892
893static zone_type*
894find_or_create_zone(namedb_type* db, const dname_type* zone_name,
895	struct nsd_options* opt, const char* zstr, const char* patname)
896{
897	zone_type* zone;
898	struct zone_options* zopt;
899	zone = namedb_find_zone(db, zone_name);
900	if(zone) {
901		return zone;
902	}
903	zopt = zone_options_find(opt, zone_name);
904	if(!zopt) {
905		/* if _implicit_ then insert as _part_of_config */
906		if(strncmp(patname, PATTERN_IMPLICIT_MARKER,
907			strlen(PATTERN_IMPLICIT_MARKER)) == 0) {
908			zopt = zone_options_create(opt->region);
909			if(!zopt) return 0;
910			zopt->part_of_config = 1;
911			zopt->name = region_strdup(opt->region, zstr);
912			zopt->pattern = pattern_options_find(opt, patname);
913			if(!zopt->name || !zopt->pattern) return 0;
914			if(!nsd_options_insert_zone(opt, zopt)) {
915				log_msg(LOG_ERR, "bad domain name or duplicate zone '%s' "
916					"pattern %s", zstr, patname);
917			}
918		} else {
919			/* create zone : presumably already added to zonelist
920			 * by xfrd, who wrote the AXFR or IXFR to disk, so we only
921			 * need to add it to our config.
922			 * This process does not need linesize and offset zonelist */
923			zopt = zone_list_zone_insert(opt, zstr, patname);
924			if(!zopt)
925				return 0;
926		}
927	}
928	zone = namedb_zone_create(db, zone_name, zopt);
929	return zone;
930}
931
932void
933delete_zone_rrs(namedb_type* db, zone_type* zone)
934{
935	rrset_type *rrset;
936	domain_type *domain = zone->apex, *next;
937	int nonexist_check = 0;
938	/* go through entire tree below the zone apex (incl subzones) */
939	while(domain && domain_is_subdomain(domain, zone->apex))
940	{
941		DEBUG(DEBUG_XFRD,2, (LOG_INFO, "delete zone visit %s",
942			domain_to_string(domain)));
943		/* delete all rrsets of the zone */
944		while((rrset = domain_find_any_rrset(domain, zone))) {
945			/* lower usage can delete other domains */
946			rrset_lower_usage(db, rrset);
947			/* rrset del does not delete our domain(yet) */
948			rrset_delete(db, domain, rrset);
949			/* no rrset_zero_nonexist_check, do that later */
950			if(domain->rrsets == 0)
951				nonexist_check = 1;
952		}
953		/* the delete upcoming could delete parents, but nothing next
954		 * or after the domain so store next ptr */
955		next = domain_next(domain);
956		/* see if the domain can be deleted (and inspect parents) */
957		domain_table_deldomain(db, domain);
958		domain = next;
959	}
960
961	/* check if data deletions have created nonexisting domain entries,
962	 * but after deleting domains so the checks are faster */
963	if(nonexist_check) {
964		domain_type* ce = NULL; /* for speeding up has_data_below */
965		DEBUG(DEBUG_XFRD, 1, (LOG_INFO, "axfrdel: zero rrset check"));
966		domain = zone->apex;
967		while(domain && domain_is_subdomain(domain, zone->apex))
968		{
969			/* the interesting domains should be existing==1
970			 * and rrsets==0, speeding up out processing of
971			 * sub-zones, since we only spuriously check empty
972			 * nonterminals */
973			if(domain->is_existing)
974				ce = rrset_zero_nonexist_check(domain, ce);
975			domain = domain_next(domain);
976		}
977	}
978
979	DEBUG(DEBUG_XFRD, 1, (LOG_INFO, "axfrdel: recyclebin holds %lu bytes",
980		(unsigned long) region_get_recycle_size(db->region)));
981#ifndef NDEBUG
982	if(nsd_debug_level >= 2)
983		region_log_stats(db->region);
984#endif
985
986	assert(zone->soa_rrset == 0);
987	/* keep zone->soa_nx_rrset alloced: it is reused */
988	assert(zone->ns_rrset == 0);
989	assert(zone->is_secure == 0);
990}
991
992/* return value 0: syntaxerror,badIXFR, 1:OK, 2:done_and_skip_it */
993static int
994apply_ixfr(nsd_type* nsd, FILE *in, uint32_t serialno,
995	uint32_t seq_nr, uint32_t seq_total,
996	int* is_axfr, int* delete_mode, int* rr_count,
997	struct zone* zone, int* bytes,
998	int* softfail, struct ixfr_store* ixfr_store)
999{
1000	uint32_t msglen, checklen, pkttype;
1001	int qcount, ancount;
1002	buffer_type* packet;
1003	region_type* region;
1004
1005	/* note that errors could not really happen due to format of the
1006	 * packet since xfrd has checked all dnames and RRs before commit,
1007	 * this is why the errors are fatal (exit process), it must be
1008	 * something internal or a bad disk or something. */
1009
1010	/* read ixfr packet RRs and apply to in memory db */
1011	if(!diff_read_32(in, &pkttype) || pkttype != DIFF_PART_XXFR) {
1012		log_msg(LOG_ERR, "could not read type or wrong type");
1013		return 0;
1014	}
1015
1016	if(!diff_read_32(in, &msglen)) {
1017		log_msg(LOG_ERR, "could not read len");
1018		return 0;
1019	}
1020
1021	if(msglen < QHEADERSZ) {
1022		log_msg(LOG_ERR, "msg too short");
1023		return 0;
1024	}
1025
1026	region = region_create(xalloc, free);
1027	if(!region) {
1028		log_msg(LOG_ERR, "out of memory");
1029		return 0;
1030	}
1031	packet = buffer_create(region, QIOBUFSZ);
1032	if(msglen > QIOBUFSZ) {
1033		log_msg(LOG_ERR, "msg too long");
1034		region_destroy(region);
1035		return 0;
1036	}
1037	buffer_clear(packet);
1038	if(fread(buffer_begin(packet), msglen, 1, in) != 1) {
1039		log_msg(LOG_ERR, "short fread: %s", strerror(errno));
1040		region_destroy(region);
1041		return 0;
1042	}
1043	buffer_set_limit(packet, msglen);
1044
1045	/* see if check on data fails: checks that we are not reading
1046	 * random garbage */
1047	if(!diff_read_32(in, &checklen) || checklen != msglen) {
1048		log_msg(LOG_ERR, "transfer part has incorrect checkvalue");
1049		return 0;
1050	}
1051	*bytes += msglen;
1052
1053	/* only answer section is really used, question, additional and
1054	   authority section RRs are skipped */
1055	qcount = QDCOUNT(packet);
1056	ancount = ANCOUNT(packet);
1057	buffer_skip(packet, QHEADERSZ);
1058	/* qcount should be 0 or 1 really, ancount limited by 64k packet */
1059	if(qcount > 64 || ancount > 65530) {
1060		log_msg(LOG_ERR, "RR count impossibly high");
1061		region_destroy(region);
1062		return 0;
1063	}
1064
1065	/* skip queries */
1066	for(int i=0; i < qcount; ++i) {
1067		if(!packet_skip_rr(packet, 1)) {
1068			log_msg(LOG_ERR, "bad RR in question section");
1069			region_destroy(region);
1070			return 0;
1071		}
1072	}
1073
1074	DEBUG(DEBUG_XFRD, 2, (LOG_INFO, "diff: started packet for zone %s",
1075			domain_to_string(zone->apex)));
1076
1077	for(int i=0; i < ancount; ++i, ++(*rr_count)) {
1078		const dname_type *owner;
1079		uint16_t type, klass, rrlen;
1080		uint32_t ttl;
1081
1082		owner = dname_make_from_packet(region, packet, 1, 1);
1083		if(!owner) {
1084			log_msg(LOG_ERR, "bad xfr RR dname %d", *rr_count);
1085			region_destroy(region);
1086			return 0;
1087		}
1088		if(!buffer_available(packet, 10)) {
1089			log_msg(LOG_ERR, "bad xfr RR format %d", *rr_count);
1090			region_destroy(region);
1091			return 0;
1092		}
1093		type = buffer_read_u16(packet);
1094		klass = buffer_read_u16(packet);
1095		ttl = buffer_read_u32(packet);
1096		rrlen = buffer_read_u16(packet);
1097		if(!buffer_available(packet, rrlen)) {
1098			log_msg(LOG_ERR, "bad xfr RR rdata %d, len %d have %d",
1099				*rr_count, rrlen, (int)buffer_remaining(packet));
1100			region_destroy(region);
1101			return 0;
1102		}
1103
1104		DEBUG(DEBUG_XFRD,2, (LOG_INFO, "diff: %s parsed count %d, ax %d, delmode %d",
1105			domain_to_string(zone->apex), *rr_count, *is_axfr, *delete_mode));
1106
1107		if (type == TYPE_SOA) {
1108			size_t position;
1109			uint32_t serial;
1110			position = buffer_position(packet);
1111			if (!packet_skip_dname(packet) ||
1112					!packet_skip_dname(packet) ||
1113					buffer_remaining(packet) < sizeof(uint32_t) * 5)
1114			{
1115				log_msg(LOG_ERR, "bad xfr SOA RR formerr.");
1116				region_destroy(region);
1117				return 0;
1118			}
1119
1120			serial = buffer_read_u32(packet);
1121			buffer_set_position(packet, position);
1122
1123			/* first RR: check if SOA and correct zone & serialno */
1124			if (*rr_count == 0) {
1125				assert(!*is_axfr);
1126				assert(!*delete_mode);
1127				if (klass != CLASS_IN) {
1128					log_msg(LOG_ERR, "first RR not SOA IN");
1129					region_destroy(region);
1130					return 0;
1131				}
1132				if(dname_compare(domain_dname(zone->apex), owner) != 0) {
1133					log_msg(LOG_ERR, "SOA dname not equal to zone %s",
1134						domain_to_string(zone->apex));
1135					region_destroy(region);
1136					return 0;
1137				}
1138				if(serial != serialno) {
1139					log_msg(LOG_ERR, "SOA serial %u different from commit %u",
1140						(unsigned)serial, (unsigned)serialno);
1141					region_destroy(region);
1142					return 0;
1143				}
1144				buffer_skip(packet, rrlen);
1145
1146				if(ixfr_store)
1147					ixfr_store_add_newsoa(ixfr_store, ttl, packet, rrlen);
1148
1149				continue;
1150			} else if (*rr_count == 1) {
1151				assert(!*is_axfr);
1152				assert(!*delete_mode);
1153				/* if the serial no of the SOA equals the serialno, then AXFR */
1154				if (serial == serialno)
1155					goto axfr;
1156				*delete_mode = 1;
1157				/* must have stuff in memory for a successful IXFR,
1158				 * the serial number of the SOA has been checked
1159				 * previously (by check_for_bad_serial) if it exists */
1160				if(!domain_find_rrset(zone->apex, zone, TYPE_SOA)) {
1161					log_msg(LOG_ERR, "%s SOA serial %u is not "
1162						"in memory, skip IXFR", domain_to_string(zone->apex), serialno);
1163					region_destroy(region);
1164					/* break out and stop the IXFR, ignore it */
1165					return 2;
1166				}
1167
1168				if(ixfr_store)
1169					ixfr_store_add_oldsoa(ixfr_store, ttl, packet, rrlen);
1170			} else if (!*is_axfr) {
1171				/* do not delete final SOA RR for IXFR */
1172				if (i == ancount - 1 && seq_nr == seq_total - 1) {
1173					if (ixfr_store) {
1174						ixfr_store_add_newsoa(ixfr_store, ttl, packet, rrlen);
1175					}
1176					*delete_mode = 0;
1177					buffer_skip(packet, rrlen);
1178					continue;
1179				} else
1180					*delete_mode = !*delete_mode;
1181
1182				if (ixfr_store && *delete_mode) {
1183					ixfr_store_add_newsoa(ixfr_store, ttl, packet, rrlen);
1184					ixfr_store_finish(ixfr_store, nsd, NULL);
1185					ixfr_store_start(zone, ixfr_store);
1186					ixfr_store_add_oldsoa(ixfr_store, ttl, packet, rrlen);
1187				}
1188				/* switch from delete-part to add-part and back again,
1189				   just before soa - so it gets deleted and added too */
1190				DEBUG(DEBUG_XFRD,2, (LOG_INFO, "diff: %s IXFRswapdel count %d, ax %d, delmode %d",
1191					domain_to_string(zone->apex), *rr_count, *is_axfr, *delete_mode));
1192			}
1193		} else {
1194			if (*rr_count == 0) {
1195				log_msg(LOG_ERR, "first RR not SOA IN");
1196				region_destroy(region);
1197				return 0;
1198			/* second RR: if not SOA: this is an AXFR; delete all zone contents */
1199			} else if (*rr_count == 1) {
1200axfr:
1201				*is_axfr = 1;
1202#ifdef NSEC3
1203				nsec3_clear_precompile(nsd->db, zone);
1204				zone->nsec3_param = NULL;
1205#endif
1206				delete_zone_rrs(nsd->db, zone);
1207				if(ixfr_store) {
1208					ixfr_store_cancel(ixfr_store);
1209					ixfr_store_delixfrs(zone);
1210				}
1211				DEBUG(DEBUG_XFRD,2, (LOG_INFO, "diff: %s sawAXFR count %d, ax %d, delmode %d",
1212					domain_to_string(zone->apex), *rr_count, *is_axfr, *delete_mode));
1213			}
1214		}
1215
1216		if(type == TYPE_TSIG || type == TYPE_OPT) {
1217			/* ignore pseudo RRs */
1218			buffer_skip(packet, rrlen);
1219			continue;
1220		}
1221
1222		DEBUG(DEBUG_XFRD,2, (LOG_INFO, "xfr %s RR dname is %s type %s",
1223			*delete_mode?"del":"add",
1224			dname_to_string(owner, 0), rrtype_to_string(type)));
1225		if(*delete_mode) {
1226			assert(!*is_axfr);
1227			/* delete this rr */
1228			if(ixfr_store)
1229				ixfr_store_delrr(ixfr_store, owner, type,
1230					klass, ttl, packet, rrlen, region);
1231			if(!delete_RR(nsd->db, owner, type, klass, packet,
1232				rrlen, zone, region, softfail)) {
1233				region_destroy(region);
1234				return 0;
1235			}
1236		} else {
1237			/* add this rr */
1238			if(ixfr_store)
1239				ixfr_store_addrr(ixfr_store, owner, type,
1240					klass, ttl, packet, rrlen, region);
1241			if(!add_RR(nsd->db, owner, type, klass, ttl, packet,
1242				rrlen, zone, softfail)) {
1243				region_destroy(region);
1244				return 0;
1245			}
1246		}
1247	}
1248	region_destroy(region);
1249	return 1;
1250}
1251
1252static int
1253check_for_bad_serial(namedb_type* db, const char* zone_str, uint32_t old_serial)
1254{
1255	/* see if serial OK with in-memory serial */
1256	domain_type* domain;
1257	region_type* region = region_create(xalloc, free);
1258	const dname_type* zone_name = dname_parse(region, zone_str);
1259	zone_type* zone = 0;
1260	domain = domain_table_find(db->domains, zone_name);
1261	if(domain)
1262		zone = domain_find_zone(db, domain);
1263	if(zone && zone->apex == domain && zone->soa_rrset && old_serial)
1264	{
1265		uint32_t memserial;
1266		memcpy(&memserial, rdata_atom_data(zone->soa_rrset->rrs[0].rdatas[2]),
1267			sizeof(uint32_t));
1268		if(old_serial != ntohl(memserial)) {
1269			region_destroy(region);
1270			return 1;
1271		}
1272	}
1273	region_destroy(region);
1274	return 0;
1275}
1276
1277int
1278apply_ixfr_for_zone(nsd_type* nsd, zone_type* zone, FILE* in,
1279	struct nsd_options* ATTR_UNUSED(opt), udb_base* taskudb, udb_ptr* last_task,
1280	uint32_t xfrfilenr)
1281{
1282	char zone_buf[3072];
1283	char log_buf[5120];
1284	char patname_buf[2048];
1285
1286	uint32_t old_serial, new_serial, num_parts, type;
1287	uint64_t time_end_0, time_start_0;
1288	uint32_t time_end_1, time_start_1;
1289	uint8_t committed;
1290	uint32_t i;
1291	int num_bytes = 0;
1292	(void)last_task;
1293	assert(zone);
1294
1295	/* read zone name and serial */
1296	if(!diff_read_32(in, &type)) {
1297		log_msg(LOG_ERR, "diff file too short");
1298		return 0;
1299	}
1300	if(type != DIFF_PART_XFRF) {
1301		log_msg(LOG_ERR, "xfr file has wrong format");
1302		return 0;
1303
1304	}
1305	/* committed and num_parts are first because they need to be
1306	 * updated once the rest is written.  The log buf is not certain
1307	 * until its done, so at end of file.  The patname is in case a
1308	 * new zone is created, we know what the options-pattern is */
1309	if(!diff_read_8(in, &committed) ||
1310		!diff_read_32(in, &num_parts) ||
1311		!diff_read_64(in, &time_end_0) ||
1312		!diff_read_32(in, &time_end_1) ||
1313		!diff_read_32(in, &old_serial) ||
1314		!diff_read_32(in, &new_serial) ||
1315		!diff_read_64(in, &time_start_0) ||
1316		!diff_read_32(in, &time_start_1) ||
1317		!diff_read_str(in, zone_buf, sizeof(zone_buf)) ||
1318		!diff_read_str(in, patname_buf, sizeof(patname_buf))) {
1319		log_msg(LOG_ERR, "diff file bad commit part");
1320		return 0;
1321	}
1322
1323	/* has been read in completely */
1324	if(strcmp(zone_buf, domain_to_string(zone->apex)) != 0) {
1325		log_msg(LOG_ERR, "file %s does not match task %s",
1326			zone_buf, domain_to_string(zone->apex));
1327		return 0;
1328	}
1329	switch(committed) {
1330	case DIFF_NOT_COMMITTED:
1331		log_msg(LOG_ERR, "diff file %s was not committed", zone_buf);
1332		return 0;
1333	case DIFF_CORRUPT:
1334		log_msg(LOG_ERR, "diff file %s was corrupt", zone_buf);
1335		return 0;
1336	case DIFF_INCONSISTENT:
1337		log_msg(LOG_ERR, "diff file %s was inconsistent", zone_buf);
1338		return 0;
1339	case DIFF_VERIFIED:
1340		log_msg(LOG_INFO, "diff file %s already verified", zone_buf);
1341		break;
1342	default:
1343		break;
1344	}
1345	if(num_parts == 0) {
1346		log_msg(LOG_ERR, "diff file %s was not completed", zone_buf);
1347		return 0;
1348	}
1349	if(check_for_bad_serial(nsd->db, zone_buf, old_serial)) {
1350		DEBUG(DEBUG_XFRD,1, (LOG_ERR,
1351			"skipping diff file commit with bad serial"));
1352		return -2; /* Success in "main" process, failure in "xfrd" */
1353	}
1354
1355	if(!zone->is_skipped)
1356	{
1357		int is_axfr=0, delete_mode=0, rr_count=0, softfail=0;
1358		struct ixfr_store* ixfr_store = NULL, ixfr_store_mem;
1359
1360		DEBUG(DEBUG_XFRD,1, (LOG_INFO, "processing xfr: %s", zone_buf));
1361		if(zone_is_ixfr_enabled(zone))
1362			ixfr_store = ixfr_store_start(zone, &ixfr_store_mem);
1363		/* read and apply all of the parts */
1364		for(i=0; i<num_parts; i++) {
1365			int ret;
1366			DEBUG(DEBUG_XFRD,2, (LOG_INFO, "processing xfr: apply part %d", (int)i));
1367			ret = apply_ixfr(nsd, in, new_serial,
1368				i, num_parts, &is_axfr, &delete_mode,
1369				&rr_count, zone,
1370				&num_bytes, &softfail, ixfr_store);
1371			if(ret == 0) {
1372				log_msg(LOG_ERR, "bad ixfr packet part %d in diff file for %s", (int)i, zone_buf);
1373				diff_update_commit(
1374					zone_buf, DIFF_CORRUPT, nsd, xfrfilenr);
1375				/* the udb is still dirty, it is bad */
1376				return -1; /* Fatal! */
1377			} else if(ret == 2) {
1378				break;
1379			}
1380		}
1381		/* read the final log_str: but do not fail on it */
1382		if(!diff_read_str(in, log_buf, sizeof(log_buf))) {
1383			log_msg(LOG_ERR, "could not read log for transfer %s",
1384				zone_buf);
1385			snprintf(log_buf, sizeof(log_buf), "error reading log");
1386		}
1387#ifdef NSEC3
1388		prehash_zone(nsd->db, zone);
1389#endif /* NSEC3 */
1390		zone->is_changed = 1;
1391		zone->is_updated = 1;
1392		zone->is_checked = (committed == DIFF_VERIFIED);
1393		zone->mtime.tv_sec = time_end_0;
1394		zone->mtime.tv_nsec = time_end_1*1000;
1395		if(zone->logstr)
1396			region_recycle(nsd->db->region, zone->logstr,
1397				strlen(zone->logstr)+1);
1398		zone->logstr = region_strdup(nsd->db->region, log_buf);
1399		if(zone->filename)
1400			region_recycle(nsd->db->region, zone->filename,
1401				strlen(zone->filename)+1);
1402		zone->filename = NULL;
1403		if(softfail && taskudb && !is_axfr) {
1404			log_msg(LOG_ERR, "Failed to apply IXFR cleanly "
1405				"(deletes nonexistent RRs, adds existing RRs). "
1406				"Zone %s contents is different from primary, "
1407				"starting AXFR. Transfer %s", zone_buf, log_buf);
1408			/* add/del failures in IXFR, get an AXFR */
1409			diff_update_commit(
1410				zone_buf, DIFF_INCONSISTENT, nsd, xfrfilenr);
1411			return -1; /* Fatal! */
1412		}
1413		if(ixfr_store)
1414			ixfr_store_finish(ixfr_store, nsd, log_buf);
1415
1416		if(1 <= verbosity) {
1417			double elapsed = (double)(time_end_0 - time_start_0)+
1418				(double)((double)time_end_1
1419				-(double)time_start_1) / 1000000.0;
1420			VERBOSITY(1, (LOG_INFO, "zone %s %s of %d bytes in %g seconds",
1421				zone_buf, log_buf, num_bytes, elapsed));
1422		}
1423	}
1424	else {
1425		DEBUG(DEBUG_XFRD,1, (LOG_INFO, "skipping xfr: %s", zone_buf));
1426	}
1427	return 1;
1428}
1429
1430static void udb_task_walk_chunk(void* base, void* d, uint64_t s, udb_walk_relptr_cb* cb, void *arg)
1431{
1432  struct task_list_d* p = (struct task_list_d*)d;
1433  assert(s >= p->size);
1434  (void)s;
1435  (*cb)(base, &p->next, arg);
1436}
1437
1438void udb_walkfunc(void* base, void* warg, uint8_t t, void* d, uint64_t s,
1439  udb_walk_relptr_cb* cb, void *arg)
1440{
1441  (void)warg;
1442  switch(t) {
1443  case udb_chunk_type_task:
1444    udb_task_walk_chunk(base, d, s, cb, arg);
1445    break;
1446  default:
1447    /* no rel ptrs */
1448    break;
1449  }
1450}
1451
1452struct udb_base* task_file_create(const char* file)
1453{
1454	return udb_base_create_new(file, &udb_walkfunc, NULL);
1455}
1456
1457static int
1458task_create_new_elem(struct udb_base* udb, udb_ptr* last, udb_ptr* e,
1459	size_t sz, const dname_type* zname)
1460{
1461	if(!udb_ptr_alloc_space(e, udb, udb_chunk_type_task, sz)) {
1462		return 0;
1463	}
1464	if(udb_ptr_is_null(last)) {
1465		udb_base_set_userdata(udb, e->data);
1466	} else {
1467		udb_rptr_set_ptr(&TASKLIST(last)->next, udb, e);
1468	}
1469	udb_ptr_set_ptr(last, udb, e);
1470
1471	/* fill in tasklist item */
1472	udb_rel_ptr_init(&TASKLIST(e)->next);
1473	TASKLIST(e)->size = sz;
1474	TASKLIST(e)->oldserial = 0;
1475	TASKLIST(e)->newserial = 0;
1476	TASKLIST(e)->yesno = 0;
1477
1478	if(zname) {
1479		memmove(TASKLIST(e)->zname, zname, dname_total_size(zname));
1480	}
1481	return 1;
1482}
1483
1484void task_new_soainfo(struct udb_base* udb, udb_ptr* last, struct zone* z,
1485	enum soainfo_hint hint)
1486{
1487	/* calculate size */
1488	udb_ptr e;
1489	size_t sz;
1490	const dname_type* apex, *ns, *em;
1491	if(!z || !z->apex || !domain_dname(z->apex))
1492		return; /* safety check */
1493
1494	DEBUG(DEBUG_IPC,1, (LOG_INFO, "nsd: add soa info for zone %s",
1495		domain_to_string(z->apex)));
1496	apex = domain_dname(z->apex);
1497	sz = sizeof(struct task_list_d) + dname_total_size(apex);
1498	if(z->soa_rrset && hint == soainfo_ok) {
1499		ns = domain_dname(rdata_atom_domain(
1500			z->soa_rrset->rrs[0].rdatas[0]));
1501		em = domain_dname(rdata_atom_domain(
1502			z->soa_rrset->rrs[0].rdatas[1]));
1503		sz += sizeof(uint32_t)*6 + sizeof(uint8_t)*2
1504			+ ns->name_size + em->name_size;
1505	} else {
1506		ns = 0;
1507		em = 0;
1508	}
1509
1510	/* create new task_list item */
1511	if(!task_create_new_elem(udb, last, &e, sz, apex)) {
1512		log_msg(LOG_ERR, "tasklist: out of space, cannot add SOAINFO");
1513		return;
1514	}
1515	TASKLIST(&e)->task_type = task_soa_info;
1516	TASKLIST(&e)->yesno = (uint64_t)hint;
1517
1518	if(z->soa_rrset && hint == soainfo_ok) {
1519		uint32_t ttl = htonl(z->soa_rrset->rrs[0].ttl);
1520		uint8_t* p = (uint8_t*)TASKLIST(&e)->zname;
1521		p += dname_total_size(apex);
1522		memmove(p, &ttl, sizeof(uint32_t));
1523		p += sizeof(uint32_t);
1524		memmove(p, &ns->name_size, sizeof(uint8_t));
1525		p += sizeof(uint8_t);
1526		memmove(p, dname_name(ns), ns->name_size);
1527		p += ns->name_size;
1528		memmove(p, &em->name_size, sizeof(uint8_t));
1529		p += sizeof(uint8_t);
1530		memmove(p, dname_name(em), em->name_size);
1531		p += em->name_size;
1532		memmove(p, rdata_atom_data(z->soa_rrset->rrs[0].rdatas[2]),
1533			sizeof(uint32_t));
1534		p += sizeof(uint32_t);
1535		memmove(p, rdata_atom_data(z->soa_rrset->rrs[0].rdatas[3]),
1536			sizeof(uint32_t));
1537		p += sizeof(uint32_t);
1538		memmove(p, rdata_atom_data(z->soa_rrset->rrs[0].rdatas[4]),
1539			sizeof(uint32_t));
1540		p += sizeof(uint32_t);
1541		memmove(p, rdata_atom_data(z->soa_rrset->rrs[0].rdatas[5]),
1542			sizeof(uint32_t));
1543		p += sizeof(uint32_t);
1544		memmove(p, rdata_atom_data(z->soa_rrset->rrs[0].rdatas[6]),
1545			sizeof(uint32_t));
1546	}
1547	udb_ptr_unlink(&e, udb);
1548}
1549
1550void task_process_sync(struct udb_base* taskudb)
1551{
1552	/* need to sync before other process uses the mmap? */
1553	DEBUG(DEBUG_IPC,1, (LOG_INFO, "task procsync %s size %d",
1554		taskudb->fname, (int)taskudb->base_size));
1555	(void)taskudb;
1556}
1557
1558void task_remap(struct udb_base* taskudb)
1559{
1560	DEBUG(DEBUG_IPC,1, (LOG_INFO, "task remap %s size %d",
1561		taskudb->fname, (int)taskudb->glob_data->fsize));
1562	udb_base_remap_process(taskudb);
1563}
1564
1565void task_clear(struct udb_base* taskudb)
1566{
1567	udb_ptr t, n;
1568	udb_ptr_new(&t, taskudb, udb_base_get_userdata(taskudb));
1569	udb_base_set_userdata(taskudb, 0);
1570	udb_ptr_init(&n, taskudb);
1571	while(!udb_ptr_is_null(&t)) {
1572		udb_ptr_set_rptr(&n, taskudb, &TASKLIST(&t)->next);
1573		udb_rptr_zero(&TASKLIST(&t)->next, taskudb);
1574		udb_ptr_free_space(&t, taskudb, TASKLIST(&t)->size);
1575		udb_ptr_set_ptr(&t, taskudb, &n);
1576	}
1577	udb_ptr_unlink(&t, taskudb);
1578	udb_ptr_unlink(&n, taskudb);
1579}
1580
1581void task_new_expire(struct udb_base* udb, udb_ptr* last,
1582	const struct dname* z, int expired)
1583{
1584	udb_ptr e;
1585	if(!z) return;
1586	DEBUG(DEBUG_IPC,1, (LOG_INFO, "add expire info for zone %s",
1587		dname_to_string(z,NULL)));
1588	if(!task_create_new_elem(udb, last, &e, sizeof(struct task_list_d)+
1589		dname_total_size(z), z)) {
1590		log_msg(LOG_ERR, "tasklist: out of space, cannot add expire");
1591		return;
1592	}
1593	TASKLIST(&e)->task_type = task_expire;
1594	TASKLIST(&e)->yesno = expired;
1595	udb_ptr_unlink(&e, udb);
1596}
1597
1598void task_new_check_zonefiles(udb_base* udb, udb_ptr* last,
1599	const dname_type* zone)
1600{
1601	udb_ptr e;
1602	xfrd_check_catalog_consumer_zonefiles(zone);
1603	DEBUG(DEBUG_IPC,1, (LOG_INFO, "add task checkzonefiles"));
1604	if(!task_create_new_elem(udb, last, &e, sizeof(struct task_list_d) +
1605		(zone?dname_total_size(zone):0), zone)) {
1606		log_msg(LOG_ERR, "tasklist: out of space, cannot add check_zones");
1607		return;
1608	}
1609	TASKLIST(&e)->task_type = task_check_zonefiles;
1610	TASKLIST(&e)->yesno = (zone!=NULL);
1611	udb_ptr_unlink(&e, udb);
1612}
1613
1614void task_new_write_zonefiles(udb_base* udb, udb_ptr* last,
1615	const dname_type* zone)
1616{
1617	udb_ptr e;
1618	DEBUG(DEBUG_IPC,1, (LOG_INFO, "add task writezonefiles"));
1619	if(!task_create_new_elem(udb, last, &e, sizeof(struct task_list_d) +
1620		(zone?dname_total_size(zone):0), zone)) {
1621		log_msg(LOG_ERR, "tasklist: out of space, cannot add writezones");
1622		return;
1623	}
1624	TASKLIST(&e)->task_type = task_write_zonefiles;
1625	TASKLIST(&e)->yesno = (zone!=NULL);
1626	udb_ptr_unlink(&e, udb);
1627}
1628
1629void task_new_set_verbosity(udb_base* udb, udb_ptr* last, int v)
1630{
1631	udb_ptr e;
1632	DEBUG(DEBUG_IPC,1, (LOG_INFO, "add task set_verbosity"));
1633	if(!task_create_new_elem(udb, last, &e, sizeof(struct task_list_d),
1634		NULL)) {
1635		log_msg(LOG_ERR, "tasklist: out of space, cannot add set_v");
1636		return;
1637	}
1638	TASKLIST(&e)->task_type = task_set_verbosity;
1639	TASKLIST(&e)->yesno = v;
1640	udb_ptr_unlink(&e, udb);
1641}
1642
1643void
1644task_new_add_zone(udb_base* udb, udb_ptr* last, const char* zone,
1645	const char* pattern, unsigned zonestatid)
1646{
1647	size_t zlen = strlen(zone);
1648	size_t plen = strlen(pattern);
1649	void *p;
1650	udb_ptr e;
1651	DEBUG(DEBUG_IPC,1, (LOG_INFO, "add task addzone %s %s", zone, pattern));
1652	if(!task_create_new_elem(udb, last, &e, sizeof(struct task_list_d)+
1653		zlen + 1 + plen + 1, NULL)) {
1654		log_msg(LOG_ERR, "tasklist: out of space, cannot add addz");
1655		return;
1656	}
1657	TASKLIST(&e)->task_type = task_add_zone;
1658	TASKLIST(&e)->yesno = zonestatid;
1659	p = TASKLIST(&e)->zname;
1660	memcpy(p, zone, zlen+1);
1661	memmove((char*)p+zlen+1, pattern, plen+1);
1662	udb_ptr_unlink(&e, udb);
1663}
1664
1665void
1666task_new_del_zone(udb_base* udb, udb_ptr* last, const dname_type* dname)
1667{
1668	udb_ptr e;
1669	DEBUG(DEBUG_IPC,1, (LOG_INFO, "add task delzone %s", dname_to_string(dname, 0)));
1670	if(!task_create_new_elem(udb, last, &e, sizeof(struct task_list_d)
1671		+dname_total_size(dname), dname)) {
1672		log_msg(LOG_ERR, "tasklist: out of space, cannot add delz");
1673		return;
1674	}
1675	TASKLIST(&e)->task_type = task_del_zone;
1676	udb_ptr_unlink(&e, udb);
1677}
1678
1679void task_new_add_key(udb_base* udb, udb_ptr* last, struct key_options* key)
1680{
1681	char* p;
1682	udb_ptr e;
1683	assert(key->name && key->algorithm && key->secret);
1684	DEBUG(DEBUG_IPC,1, (LOG_INFO, "add task addkey"));
1685	if(!task_create_new_elem(udb, last, &e, sizeof(struct task_list_d)
1686		+strlen(key->name)+1+strlen(key->algorithm)+1+
1687		strlen(key->secret)+1, NULL)) {
1688		log_msg(LOG_ERR, "tasklist: out of space, cannot add addk");
1689		return;
1690	}
1691	TASKLIST(&e)->task_type = task_add_key;
1692	p = (char*)TASKLIST(&e)->zname;
1693	memmove(p, key->name, strlen(key->name)+1);
1694	p+=strlen(key->name)+1;
1695	memmove(p, key->algorithm, strlen(key->algorithm)+1);
1696	p+=strlen(key->algorithm)+1;
1697	memmove(p, key->secret, strlen(key->secret)+1);
1698	udb_ptr_unlink(&e, udb);
1699}
1700
1701void task_new_del_key(udb_base* udb, udb_ptr* last, const char* name)
1702{
1703	char* p;
1704	udb_ptr e;
1705	DEBUG(DEBUG_IPC,1, (LOG_INFO, "add task delkey"));
1706	if(!task_create_new_elem(udb, last, &e, sizeof(struct task_list_d)
1707		+strlen(name)+1, NULL)) {
1708		log_msg(LOG_ERR, "tasklist: out of space, cannot add delk");
1709		return;
1710	}
1711	TASKLIST(&e)->task_type = task_del_key;
1712	p = (char*)TASKLIST(&e)->zname;
1713	memmove(p, name, strlen(name)+1);
1714	udb_ptr_unlink(&e, udb);
1715}
1716
1717void task_new_add_cookie_secret(udb_base* udb, udb_ptr* last,
1718                                 const char* secret) {
1719	udb_ptr e;
1720	char* p;
1721	size_t const secret_size = strlen(secret) + 1;
1722
1723	DEBUG(DEBUG_IPC, 1, (LOG_INFO, "add task add_cookie_secret"));
1724
1725	if(!task_create_new_elem(udb, last, &e,
1726	                         sizeof(struct task_list_d) + secret_size, NULL)) {
1727		log_msg(LOG_ERR, "tasklist: out of space, cannot add add_cookie_secret");
1728		return;
1729	}
1730	TASKLIST(&e)->task_type = task_add_cookie_secret;
1731	p = (char*)TASKLIST(&e)->zname;
1732	memmove(p, secret, secret_size);
1733	udb_ptr_unlink(&e, udb);
1734}
1735
1736void task_new_drop_cookie_secret(udb_base* udb, udb_ptr* last) {
1737	udb_ptr e;
1738	DEBUG(DEBUG_IPC, 1, (LOG_INFO, "add task drop_cookie_secret"));
1739	if(!task_create_new_elem(udb, last, &e, sizeof(struct task_list_d), NULL)) {
1740		log_msg(LOG_ERR, "tasklist: out of space, cannot add drop_cookie_secret");
1741		return;
1742	}
1743	TASKLIST(&e)->task_type = task_drop_cookie_secret;
1744	udb_ptr_unlink(&e, udb);
1745}
1746
1747void task_new_activate_cookie_secret(udb_base* udb, udb_ptr* last) {
1748	udb_ptr e;
1749	DEBUG(DEBUG_IPC, 1, (LOG_INFO, "add task activate_cookie_secret"));
1750	if(!task_create_new_elem(udb, last, &e, sizeof(struct task_list_d), NULL)) {
1751		log_msg(LOG_ERR, "tasklist: out of space, cannot add activate_cookie_secret");
1752		return;
1753	}
1754	TASKLIST(&e)->task_type = task_activate_cookie_secret;
1755	udb_ptr_unlink(&e, udb);
1756}
1757
1758void task_new_add_pattern(udb_base* udb, udb_ptr* last,
1759	struct pattern_options* p)
1760{
1761	region_type* temp;
1762	buffer_type* buffer;
1763	udb_ptr e;
1764	DEBUG(DEBUG_IPC,1, (LOG_INFO, "add task addpattern %s", p->pname));
1765	temp = region_create(xalloc, free);
1766	buffer = buffer_create(temp, 4096);
1767	pattern_options_marshal(buffer, p);
1768	buffer_flip(buffer);
1769	if(!task_create_new_elem(udb, last, &e, sizeof(struct task_list_d)
1770		+ buffer_limit(buffer), NULL)) {
1771		log_msg(LOG_ERR, "tasklist: out of space, cannot add addp");
1772		region_destroy(temp);
1773		return;
1774	}
1775	TASKLIST(&e)->task_type = task_add_pattern;
1776	TASKLIST(&e)->yesno = buffer_limit(buffer);
1777	memmove(TASKLIST(&e)->zname, buffer_begin(buffer),
1778		buffer_limit(buffer));
1779	udb_ptr_unlink(&e, udb);
1780	region_destroy(temp);
1781}
1782
1783void task_new_del_pattern(udb_base* udb, udb_ptr* last, const char* name)
1784{
1785	char* p;
1786	udb_ptr e;
1787	DEBUG(DEBUG_IPC,1, (LOG_INFO, "add task delpattern %s", name));
1788	if(!task_create_new_elem(udb, last, &e, sizeof(struct task_list_d)
1789		+strlen(name)+1, NULL)) {
1790		log_msg(LOG_ERR, "tasklist: out of space, cannot add delp");
1791		return;
1792	}
1793	TASKLIST(&e)->task_type = task_del_pattern;
1794	p = (char*)TASKLIST(&e)->zname;
1795	memmove(p, name, strlen(name)+1);
1796	udb_ptr_unlink(&e, udb);
1797}
1798
1799void task_new_opt_change(udb_base* udb, udb_ptr* last, struct nsd_options* opt)
1800{
1801	udb_ptr e;
1802	DEBUG(DEBUG_IPC,1, (LOG_INFO, "add task opt_change"));
1803	if(!task_create_new_elem(udb, last, &e, sizeof(struct task_list_d),
1804		NULL)) {
1805		log_msg(LOG_ERR, "tasklist: out of space, cannot add o_c");
1806		return;
1807	}
1808	TASKLIST(&e)->task_type = task_opt_change;
1809#ifdef RATELIMIT
1810	TASKLIST(&e)->oldserial = opt->rrl_ratelimit;
1811	TASKLIST(&e)->newserial = opt->rrl_whitelist_ratelimit;
1812	TASKLIST(&e)->yesno = (uint64_t) opt->rrl_slip;
1813#else
1814	(void)opt;
1815#endif
1816	udb_ptr_unlink(&e, udb);
1817}
1818
1819void task_new_zonestat_inc(udb_base* udb, udb_ptr* last, unsigned sz)
1820{
1821	udb_ptr e;
1822	DEBUG(DEBUG_IPC,1, (LOG_INFO, "add task zonestat_inc"));
1823	if(sz == 0)
1824		return; /* no need to decrease to 0 */
1825	if(!task_create_new_elem(udb, last, &e, sizeof(struct task_list_d),
1826		NULL)) {
1827		log_msg(LOG_ERR, "tasklist: out of space, cannot add z_i");
1828		return;
1829	}
1830	TASKLIST(&e)->task_type = task_zonestat_inc;
1831	TASKLIST(&e)->oldserial = (uint32_t)sz;
1832	udb_ptr_unlink(&e, udb);
1833}
1834
1835int
1836task_new_apply_xfr(udb_base* udb, udb_ptr* last, const dname_type* dname,
1837	uint32_t old_serial, uint32_t new_serial, uint64_t filenumber)
1838{
1839	udb_ptr e;
1840	DEBUG(DEBUG_IPC,1, (LOG_INFO, "add task apply_xfr"));
1841	if(!task_create_new_elem(udb, last, &e, sizeof(struct task_list_d)
1842		+dname_total_size(dname), dname)) {
1843		log_msg(LOG_ERR, "tasklist: out of space, cannot add applyxfr");
1844		return 0;
1845	}
1846	TASKLIST(&e)->oldserial = old_serial;
1847	TASKLIST(&e)->newserial = new_serial;
1848	TASKLIST(&e)->yesno = filenumber;
1849	TASKLIST(&e)->task_type = task_apply_xfr;
1850	udb_ptr_unlink(&e, udb);
1851	return 1;
1852}
1853
1854void
1855task_process_expire(namedb_type* db, struct task_list_d* task)
1856{
1857	uint8_t ok;
1858	zone_type* z = namedb_find_zone(db, task->zname);
1859	assert(task->task_type == task_expire);
1860	if(!z) {
1861		DEBUG(DEBUG_IPC, 1, (LOG_WARNING, "zone %s %s but not in zonetree",
1862			dname_to_string(task->zname, NULL),
1863			task->yesno?"expired":"unexpired"));
1864		return;
1865	}
1866	DEBUG(DEBUG_IPC,1, (LOG_INFO, "xfrd: expire task zone %s %s",
1867		dname_to_string(task->zname,0),
1868		task->yesno?"expired":"unexpired"));
1869	/* find zone, set expire flag */
1870	ok = !task->yesno;
1871	/* only update zone->is_ok if needed to minimize copy-on-write
1872	 * of memory pages shared after fork() */
1873	if(ok && !z->is_ok)
1874		z->is_ok = 1;
1875	else if(!ok && z->is_ok)
1876		z->is_ok = 0;
1877}
1878
1879static void
1880task_process_set_verbosity(struct task_list_d* task)
1881{
1882	DEBUG(DEBUG_IPC,1, (LOG_INFO, "verbosity task %d", (int)task->yesno));
1883	verbosity = task->yesno;
1884}
1885
1886static void
1887task_process_checkzones(struct nsd* nsd, udb_base* taskudb, udb_ptr* last_task,
1888	struct task_list_d* task)
1889{
1890	/* on SIGHUP check if zone-text-files changed and if so,
1891	 * reread.  When from xfrd-reload, no need to fstat the files */
1892	if(task->yesno) {
1893		struct zone_options* zo = zone_options_find(nsd->options,
1894			task->zname);
1895		if(zo)
1896			namedb_check_zonefile(nsd, taskudb, last_task, zo);
1897	} else {
1898		/* check all zones */
1899		namedb_check_zonefiles(nsd, nsd->options, taskudb, last_task);
1900	}
1901}
1902
1903static void
1904task_process_writezones(struct nsd* nsd, struct task_list_d* task)
1905{
1906	if(task->yesno) {
1907		struct zone_options* zo = zone_options_find(nsd->options,
1908			task->zname);
1909		if(zo)
1910			namedb_write_zonefile(nsd, zo);
1911	} else {
1912		namedb_write_zonefiles(nsd, nsd->options);
1913	}
1914}
1915
1916static void
1917task_process_add_zone(struct nsd* nsd, udb_base* udb, udb_ptr* last_task,
1918	struct task_list_d* task)
1919{
1920	zone_type* z;
1921	const dname_type* zdname;
1922	const char* zname = (const char*)task->zname;
1923	const char* pname = zname + strlen(zname)+1;
1924	DEBUG(DEBUG_IPC,1, (LOG_INFO, "addzone task %s %s", zname, pname));
1925	zdname = dname_parse(nsd->db->region, zname);
1926	if(!zdname) {
1927		log_msg(LOG_ERR, "can not parse zone name %s", zname);
1928		return;
1929	}
1930	/* create zone */
1931	z = find_or_create_zone(nsd->db, zdname, nsd->options, zname, pname);
1932	if(!z) {
1933		region_recycle(nsd->db->region, (void*)zdname,
1934			dname_total_size(zdname));
1935		log_msg(LOG_ERR, "can not add zone %s %s", zname, pname);
1936		return;
1937	}
1938	z->zonestatid = (unsigned)task->yesno;
1939	/* if zone is empty, attempt to read the zonefile from disk (if any) */
1940	if(!z->soa_rrset && z->opts->pattern->zonefile) {
1941		namedb_read_zonefile(nsd, z, udb, last_task);
1942	}
1943}
1944
1945static void
1946task_process_del_zone(struct nsd* nsd, struct task_list_d* task)
1947{
1948	zone_type* zone;
1949	struct zone_options* zopt;
1950	DEBUG(DEBUG_IPC,1, (LOG_INFO, "delzone task %s", dname_to_string(
1951		task->zname, NULL)));
1952	zone = namedb_find_zone(nsd->db, task->zname);
1953	if(!zone)
1954		return;
1955
1956#ifdef NSEC3
1957	nsec3_clear_precompile(nsd->db, zone);
1958	zone->nsec3_param = NULL;
1959#endif
1960	delete_zone_rrs(nsd->db, zone);
1961
1962	/* remove from zonetree, apex, soa */
1963	zopt = zone->opts;
1964	namedb_zone_delete(nsd->db, zone);
1965	/* remove from options (zone_list already edited by xfrd) */
1966	zone_options_delete(nsd->options, zopt);
1967}
1968
1969static void
1970task_process_add_key(struct nsd* nsd, struct task_list_d* task)
1971{
1972	struct key_options key;
1973	key.name = (char*)task->zname;
1974	DEBUG(DEBUG_IPC,1, (LOG_INFO, "addkey task %s", key.name));
1975	key.algorithm = key.name + strlen(key.name)+1;
1976	key.secret = key.algorithm + strlen(key.algorithm)+1;
1977	key_options_add_modify(nsd->options, &key);
1978	memset(key.secret, 0xdd, strlen(key.secret)); /* wipe secret */
1979}
1980
1981static void
1982task_process_del_key(struct nsd* nsd, struct task_list_d* task)
1983{
1984	char* name = (char*)task->zname;
1985	DEBUG(DEBUG_IPC,1, (LOG_INFO, "delkey task %s", name));
1986	/* this is reload and nothing is using the TSIG key right now */
1987	key_options_remove(nsd->options, name);
1988}
1989
1990static void
1991task_process_add_cookie_secret(struct nsd* nsd, struct task_list_d* task) {
1992	uint8_t secret_tmp[NSD_COOKIE_SECRET_SIZE];
1993	ssize_t decoded_len;
1994	char* secret = (char*)task->zname;
1995
1996	DEBUG(DEBUG_IPC, 1, (LOG_INFO, "add_cookie_secret task %s", secret));
1997
1998	if( strlen(secret) != 32 ) {
1999		log_msg(LOG_ERR, "invalid cookie secret: %s", secret);
2000		explicit_bzero(secret, strlen(secret));
2001		return;
2002	}
2003
2004	decoded_len = hex_pton(secret, secret_tmp, NSD_COOKIE_SECRET_SIZE);
2005	if( decoded_len != 16 ) {
2006		explicit_bzero(secret_tmp, NSD_COOKIE_SECRET_SIZE);
2007		log_msg(LOG_ERR, "unable to parse cookie secret: %s", secret);
2008		explicit_bzero(secret, strlen(secret));
2009		return;
2010	}
2011	explicit_bzero(secret, strlen(secret));
2012	add_cookie_secret(nsd, secret_tmp);
2013	explicit_bzero(secret_tmp, NSD_COOKIE_SECRET_SIZE);
2014}
2015
2016static void
2017task_process_drop_cookie_secret(struct nsd* nsd, struct task_list_d* task)
2018{
2019	(void)task;
2020	DEBUG(DEBUG_IPC, 1, (LOG_INFO, "drop_cookie_secret task"));
2021	if( nsd->cookie_count <= 1 ) {
2022		log_msg(LOG_ERR, "can not drop the only active cookie secret");
2023		return;
2024	}
2025	drop_cookie_secret(nsd);
2026}
2027
2028static void
2029task_process_activate_cookie_secret(struct nsd* nsd, struct task_list_d* task)
2030{
2031	(void)task;
2032	DEBUG(DEBUG_IPC, 1, (LOG_INFO, "activate_cookie_secret task"));
2033	if( nsd->cookie_count <= 1 ) {
2034		log_msg(LOG_ERR, "can not activate the only active cookie secret");
2035		return;
2036	}
2037	activate_cookie_secret(nsd);
2038}
2039
2040static void
2041task_process_add_pattern(struct nsd* nsd, struct task_list_d* task)
2042{
2043	region_type* temp = region_create(xalloc, free);
2044	buffer_type buffer;
2045	struct pattern_options *pat;
2046	buffer_create_from(&buffer, task->zname, task->yesno);
2047	pat = pattern_options_unmarshal(temp, &buffer);
2048	DEBUG(DEBUG_IPC,1, (LOG_INFO, "addpattern task %s", pat->pname));
2049	pattern_options_add_modify(nsd->options, pat);
2050	region_destroy(temp);
2051}
2052
2053static void
2054task_process_del_pattern(struct nsd* nsd, struct task_list_d* task)
2055{
2056	char* name = (char*)task->zname;
2057	DEBUG(DEBUG_IPC,1, (LOG_INFO, "delpattern task %s", name));
2058	pattern_options_remove(nsd->options, name);
2059}
2060
2061static void
2062task_process_opt_change(struct nsd* nsd, struct task_list_d* task)
2063{
2064	DEBUG(DEBUG_IPC,1, (LOG_INFO, "optchange task"));
2065#ifdef RATELIMIT
2066	nsd->options->rrl_ratelimit = task->oldserial;
2067	nsd->options->rrl_whitelist_ratelimit = task->newserial;
2068	nsd->options->rrl_slip = task->yesno;
2069	rrl_set_limit(nsd->options->rrl_ratelimit, nsd->options->rrl_whitelist_ratelimit,
2070		nsd->options->rrl_slip);
2071#else
2072	(void)nsd; (void)task;
2073#endif
2074}
2075
2076#ifdef USE_ZONE_STATS
2077static void
2078task_process_zonestat_inc(struct nsd* nsd, udb_base* udb, udb_ptr *last_task,
2079	struct task_list_d* task)
2080{
2081	DEBUG(DEBUG_IPC,1, (LOG_INFO, "zonestat_inc task %u", (unsigned)task->oldserial));
2082	nsd->zonestatdesired = (unsigned)task->oldserial;
2083	/* send echo to xfrd to increment on its end */
2084	task_new_zonestat_inc(udb, last_task, nsd->zonestatdesired);
2085}
2086#endif
2087
2088static void
2089task_process_apply_xfr(struct nsd* nsd, udb_base* udb, udb_ptr *last_task,
2090	udb_ptr* task)
2091{
2092	/* we have to use an udb_ptr task here, because the apply_xfr procedure
2093	 * appends soa_info which may remap and change the pointer. */
2094	zone_type* zone;
2095	FILE* df;
2096	DEBUG(DEBUG_IPC,1, (LOG_INFO, "applyxfr task %s", dname_to_string(
2097		TASKLIST(task)->zname, NULL)));
2098	zone = namedb_find_zone(nsd->db, TASKLIST(task)->zname);
2099	if(!zone) {
2100		/* assume the zone has been deleted and a zone transfer was
2101		 * still waiting to be processed */
2102		return;
2103	}
2104
2105	/* apply the XFR */
2106	/* oldserial, newserial, yesno is filenumber */
2107	df = xfrd_open_xfrfile(nsd, TASKLIST(task)->yesno, "r");
2108	if(!df) {
2109		/* could not open file to update */
2110		/* soainfo_gone will be communicated from server_reload, unless
2111		   preceding updates have been applied */
2112		zone->is_skipped = 1;
2113		return;
2114	}
2115	/* read and apply zone transfer */
2116	switch(apply_ixfr_for_zone(nsd, zone, df, nsd->options, udb, last_task,
2117				TASKLIST(task)->yesno)) {
2118	case 1: /* Success */
2119		break;
2120
2121	case 0: /* Failure */
2122		/* soainfo_gone will be communicated from server_reload, unless
2123		   preceding updates have been applied  */
2124		zone->is_skipped = 1;
2125		break;
2126
2127	case -1:/* Fatal */
2128		exit(1);
2129		break;
2130
2131	default:break;
2132	}
2133	fclose(df);
2134}
2135
2136
2137void task_process_in_reload(struct nsd* nsd, udb_base* udb, udb_ptr *last_task,
2138        udb_ptr* task)
2139{
2140	switch(TASKLIST(task)->task_type) {
2141	case task_expire:
2142		task_process_expire(nsd->db, TASKLIST(task));
2143		break;
2144	case task_check_zonefiles:
2145		task_process_checkzones(nsd, udb, last_task, TASKLIST(task));
2146		break;
2147	case task_write_zonefiles:
2148		task_process_writezones(nsd, TASKLIST(task));
2149		break;
2150	case task_set_verbosity:
2151		task_process_set_verbosity(TASKLIST(task));
2152		break;
2153	case task_add_zone:
2154		task_process_add_zone(nsd, udb, last_task, TASKLIST(task));
2155		break;
2156	case task_del_zone:
2157		task_process_del_zone(nsd, TASKLIST(task));
2158		break;
2159	case task_add_key:
2160		task_process_add_key(nsd, TASKLIST(task));
2161		break;
2162	case task_del_key:
2163		task_process_del_key(nsd, TASKLIST(task));
2164		break;
2165	case task_add_pattern:
2166		task_process_add_pattern(nsd, TASKLIST(task));
2167		break;
2168	case task_del_pattern:
2169		task_process_del_pattern(nsd, TASKLIST(task));
2170		break;
2171	case task_opt_change:
2172		task_process_opt_change(nsd, TASKLIST(task));
2173		break;
2174#ifdef USE_ZONE_STATS
2175	case task_zonestat_inc:
2176		task_process_zonestat_inc(nsd, udb, last_task, TASKLIST(task));
2177		break;
2178#endif
2179	case task_apply_xfr:
2180		task_process_apply_xfr(nsd, udb, last_task, task);
2181		break;
2182	case task_add_cookie_secret:
2183		task_process_add_cookie_secret(nsd, TASKLIST(task));
2184		break;
2185	case task_drop_cookie_secret:
2186		task_process_drop_cookie_secret(nsd, TASKLIST(task));
2187		break;
2188	case task_activate_cookie_secret:
2189		task_process_activate_cookie_secret(nsd, TASKLIST(task));
2190		break;
2191	default:
2192		log_msg(LOG_WARNING, "unhandled task in reload type %d",
2193			(int)TASKLIST(task)->task_type);
2194		break;
2195	}
2196	udb_ptr_free_space(task, udb, TASKLIST(task)->size);
2197}
2198