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