xref: /openbsd/usr.sbin/nsd/difffile.c (revision bf87c3c0)
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 
29 static int
write_64(FILE * out,uint64_t val)30 write_64(FILE *out, uint64_t val)
31 {
32 	return write_data(out, &val, sizeof(val));
33 }
34 
35 static int
write_32(FILE * out,uint32_t val)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
write_8(FILE * out,uint8_t val)43 write_8(FILE *out, uint8_t val)
44 {
45 	return write_data(out, &val, sizeof(val));
46 }
47 
48 static int
write_str(FILE * out,const char * str)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
diff_write_packet(const char * zone,const char * pat,uint32_t old_serial,uint32_t new_serial,uint32_t seq_nr,uint8_t * data,size_t len,struct nsd * nsd,uint64_t filenumber)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
diff_write_commit(const char * zone,uint32_t old_serial,uint32_t new_serial,uint32_t num_parts,uint8_t commit,const char * log_str,struct nsd * nsd,uint64_t filenumber)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
diff_update_commit(const char * zone,uint8_t commit,struct nsd * nsd,uint64_t filenumber)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
diff_read_64(FILE * in,uint64_t * result)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
diff_read_32(FILE * in,uint32_t * result)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
diff_read_8(FILE * in,uint8_t * result)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
diff_read_str(FILE * in,char * buf,size_t len)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
add_rdata_to_recyclebin(namedb_type * db,rr_type * rr)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
has_data_below(domain_type * top)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*
rrset_zero_nonexist_check(domain_type * domain,domain_type * ce)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
rrset_delete(namedb_type * db,domain_type * domain,rrset_type * rrset)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
rdatas_equal(rdata_atom_type * a,rdata_atom_type * b,int num,uint16_t type,int * rdnum,char ** reason)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
debug_find_rr_num(rrset_type * rrset,uint16_t type,uint16_t klass,rdata_atom_type * rdatas,ssize_t rdata_num)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
find_rr_num(rrset_type * rrset,uint16_t type,uint16_t klass,rdata_atom_type * rdatas,ssize_t rdata_num,int add)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
nsec3_delete_rr_trigger(namedb_type * db,rr_type * rr,zone_type * zone)465 nsec3_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 */
505 static void
nsec3_rrsets_changed_remove_prehash(domain_type * domain,zone_type * zone)506 nsec3_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 */
540 static void
nsec3_rrsets_changed_add_prehash(namedb_type * db,domain_type * domain,zone_type * zone)541 nsec3_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 */
561 static void
nsec3_delete_rrset_trigger(namedb_type * db,domain_type * domain,zone_type * zone,uint16_t type)562 nsec3_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 */
584 static void
nsec3_add_rr_trigger(namedb_type * db,rr_type * rr,zone_type * zone)585 nsec3_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 */
616 static void
nsec3_add_rrset_trigger(namedb_type * db,domain_type * domain,zone_type * zone,uint16_t type)617 nsec3_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 */
643 static void
rr_lower_usage(namedb_type * db,rr_type * rr)644 rr_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 
658 static void
rrset_lower_usage(namedb_type * db,rrset_type * rrset)659 rrset_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 
666 int
delete_RR(namedb_type * db,const dname_type * dname,uint16_t type,uint16_t klass,buffer_type * packet,size_t rdatalen,zone_type * zone,region_type * temp_region,int * softfail)667 delete_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 
780 int
add_RR(namedb_type * db,const dname_type * dname,uint16_t type,uint16_t klass,uint32_t ttl,buffer_type * packet,size_t rdatalen,zone_type * zone,int * softfail)781 add_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 
893 static zone_type*
find_or_create_zone(namedb_type * db,const dname_type * zone_name,struct nsd_options * opt,const char * zstr,const char * patname)894 find_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 
932 void
delete_zone_rrs(namedb_type * db,zone_type * zone)933 delete_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 */
993 static int
apply_ixfr(nsd_type * nsd,FILE * in,uint32_t serialno,uint32_t seq_nr,uint32_t seq_total,int * is_axfr,int * delete_mode,int * rr_count,struct zone * zone,int * bytes,int * softfail,struct ixfr_store * ixfr_store)994 apply_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) {
1200 axfr:
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 
1252 static int
check_for_bad_serial(namedb_type * db,const char * zone_str,uint32_t old_serial)1253 check_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 
1277 int
apply_ixfr_for_zone(nsd_type * nsd,zone_type * zone,FILE * in,struct nsd_options * ATTR_UNUSED (opt),udb_base * taskudb,udb_ptr * last_task,uint32_t xfrfilenr)1278 apply_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 
udb_task_walk_chunk(void * base,void * d,uint64_t s,udb_walk_relptr_cb * cb,void * arg)1430 static 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 
udb_walkfunc(void * base,void * warg,uint8_t t,void * d,uint64_t s,udb_walk_relptr_cb * cb,void * arg)1438 void 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 
task_file_create(const char * file)1452 struct udb_base* task_file_create(const char* file)
1453 {
1454 	return udb_base_create_new(file, &udb_walkfunc, NULL);
1455 }
1456 
1457 static int
task_create_new_elem(struct udb_base * udb,udb_ptr * last,udb_ptr * e,size_t sz,const dname_type * zname)1458 task_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 
task_new_soainfo(struct udb_base * udb,udb_ptr * last,struct zone * z,enum soainfo_hint hint)1484 void 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 
task_process_sync(struct udb_base * taskudb)1550 void 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 
task_remap(struct udb_base * taskudb)1558 void 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 
task_clear(struct udb_base * taskudb)1565 void 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 
task_new_expire(struct udb_base * udb,udb_ptr * last,const struct dname * z,int expired)1581 void 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 
task_new_check_zonefiles(udb_base * udb,udb_ptr * last,const dname_type * zone)1598 void 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 
task_new_write_zonefiles(udb_base * udb,udb_ptr * last,const dname_type * zone)1614 void 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 
task_new_set_verbosity(udb_base * udb,udb_ptr * last,int v)1629 void 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 
1643 void
task_new_add_zone(udb_base * udb,udb_ptr * last,const char * zone,const char * pattern,unsigned zonestatid)1644 task_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 
1665 void
task_new_del_zone(udb_base * udb,udb_ptr * last,const dname_type * dname)1666 task_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 
task_new_add_key(udb_base * udb,udb_ptr * last,struct key_options * key)1679 void 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 
task_new_del_key(udb_base * udb,udb_ptr * last,const char * name)1701 void 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 
task_new_add_cookie_secret(udb_base * udb,udb_ptr * last,const char * secret)1717 void 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 
task_new_drop_cookie_secret(udb_base * udb,udb_ptr * last)1736 void 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 
task_new_activate_cookie_secret(udb_base * udb,udb_ptr * last)1747 void 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 
task_new_add_pattern(udb_base * udb,udb_ptr * last,struct pattern_options * p)1758 void 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 
task_new_del_pattern(udb_base * udb,udb_ptr * last,const char * name)1783 void 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 
task_new_opt_change(udb_base * udb,udb_ptr * last,struct nsd_options * opt)1799 void 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 
task_new_zonestat_inc(udb_base * udb,udb_ptr * last,unsigned sz)1819 void 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 
1835 int
task_new_apply_xfr(udb_base * udb,udb_ptr * last,const dname_type * dname,uint32_t old_serial,uint32_t new_serial,uint64_t filenumber)1836 task_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 
1854 void
task_process_expire(namedb_type * db,struct task_list_d * task)1855 task_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 
1879 static void
task_process_set_verbosity(struct task_list_d * task)1880 task_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 
1886 static void
task_process_checkzones(struct nsd * nsd,udb_base * taskudb,udb_ptr * last_task,struct task_list_d * task)1887 task_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 
1903 static void
task_process_writezones(struct nsd * nsd,struct task_list_d * task)1904 task_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 
1916 static void
task_process_add_zone(struct nsd * nsd,udb_base * udb,udb_ptr * last_task,struct task_list_d * task)1917 task_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 
1945 static void
task_process_del_zone(struct nsd * nsd,struct task_list_d * task)1946 task_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 
1969 static void
task_process_add_key(struct nsd * nsd,struct task_list_d * task)1970 task_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 
1981 static void
task_process_del_key(struct nsd * nsd,struct task_list_d * task)1982 task_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 
1990 static void
task_process_add_cookie_secret(struct nsd * nsd,struct task_list_d * task)1991 task_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 
2016 static void
task_process_drop_cookie_secret(struct nsd * nsd,struct task_list_d * task)2017 task_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 
2028 static void
task_process_activate_cookie_secret(struct nsd * nsd,struct task_list_d * task)2029 task_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 
2040 static void
task_process_add_pattern(struct nsd * nsd,struct task_list_d * task)2041 task_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 
2053 static void
task_process_del_pattern(struct nsd * nsd,struct task_list_d * task)2054 task_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 
2061 static void
task_process_opt_change(struct nsd * nsd,struct task_list_d * task)2062 task_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
2077 static void
task_process_zonestat_inc(struct nsd * nsd,udb_base * udb,udb_ptr * last_task,struct task_list_d * task)2078 task_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 
2088 static void
task_process_apply_xfr(struct nsd * nsd,udb_base * udb,udb_ptr * last_task,udb_ptr * task)2089 task_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 
task_process_in_reload(struct nsd * nsd,udb_base * udb,udb_ptr * last_task,udb_ptr * task)2137 void 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