xref: /freebsd/contrib/unbound/services/localzone.c (revision 3a970562d7f8b2506f7bcbe378e3c02a408425d7)
1 /*
2  * services/localzone.c - local zones authority service.
3  *
4  * Copyright (c) 2007, NLnet Labs. All rights reserved.
5  *
6  * This software is open source.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * Redistributions of source code must retain the above copyright notice,
13  * this list of conditions and the following disclaimer.
14  *
15  * Redistributions in binary form must reproduce the above copyright notice,
16  * this list of conditions and the following disclaimer in the documentation
17  * and/or other materials provided with the distribution.
18  *
19  * Neither the name of the NLNET LABS nor the names of its contributors may
20  * be used to endorse or promote products derived from this software without
21  * specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27  * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
29  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34  */
35 
36 /**
37  * \file
38  *
39  * This file contains functions to enable local zone authority service.
40  */
41 #include "config.h"
42 #include "services/localzone.h"
43 #include "sldns/str2wire.h"
44 #include "sldns/sbuffer.h"
45 #include "util/regional.h"
46 #include "util/config_file.h"
47 #include "util/data/dname.h"
48 #include "util/data/packed_rrset.h"
49 #include "util/data/msgencode.h"
50 #include "util/net_help.h"
51 #include "util/netevent.h"
52 #include "util/data/msgreply.h"
53 #include "util/data/msgparse.h"
54 #include "util/as112.h"
55 
56 struct local_zones*
57 local_zones_create(void)
58 {
59 	struct local_zones* zones = (struct local_zones*)calloc(1,
60 		sizeof(*zones));
61 	if(!zones)
62 		return NULL;
63 	rbtree_init(&zones->ztree, &local_zone_cmp);
64 	lock_rw_init(&zones->lock);
65 	lock_protect(&zones->lock, &zones->ztree, sizeof(zones->ztree));
66 	/* also lock protects the rbnode's in struct local_zone */
67 	return zones;
68 }
69 
70 /** helper traverse to delete zones */
71 static void
72 lzdel(rbnode_t* n, void* ATTR_UNUSED(arg))
73 {
74 	struct local_zone* z = (struct local_zone*)n->key;
75 	local_zone_delete(z);
76 }
77 
78 void
79 local_zones_delete(struct local_zones* zones)
80 {
81 	if(!zones)
82 		return;
83 	lock_rw_destroy(&zones->lock);
84 	/* walk through zones and delete them all */
85 	traverse_postorder(&zones->ztree, lzdel, NULL);
86 	free(zones);
87 }
88 
89 void
90 local_zone_delete(struct local_zone* z)
91 {
92 	if(!z)
93 		return;
94 	lock_rw_destroy(&z->lock);
95 	regional_destroy(z->region);
96 	free(z->name);
97 	free(z->taglist);
98 	free(z);
99 }
100 
101 int
102 local_zone_cmp(const void* z1, const void* z2)
103 {
104 	/* first sort on class, so that hierarchy can be maintained within
105 	 * a class */
106 	struct local_zone* a = (struct local_zone*)z1;
107 	struct local_zone* b = (struct local_zone*)z2;
108 	int m;
109 	if(a->dclass != b->dclass) {
110 		if(a->dclass < b->dclass)
111 			return -1;
112 		return 1;
113 	}
114 	return dname_lab_cmp(a->name, a->namelabs, b->name, b->namelabs, &m);
115 }
116 
117 int
118 local_data_cmp(const void* d1, const void* d2)
119 {
120 	struct local_data* a = (struct local_data*)d1;
121 	struct local_data* b = (struct local_data*)d2;
122 	int m;
123 	return dname_canon_lab_cmp(a->name, a->namelabs, b->name,
124 		b->namelabs, &m);
125 }
126 
127 /* form wireformat from text format domain name */
128 int
129 parse_dname(const char* str, uint8_t** res, size_t* len, int* labs)
130 {
131 	*res = sldns_str2wire_dname(str, len);
132 	*labs = 0;
133 	if(!*res) {
134 		log_err("cannot parse name %s", str);
135 		return 0;
136 	}
137 	*labs = dname_count_size_labels(*res, len);
138 	return 1;
139 }
140 
141 /** create a new localzone */
142 static struct local_zone*
143 local_zone_create(uint8_t* nm, size_t len, int labs,
144 	enum localzone_type t, uint16_t dclass)
145 {
146 	struct local_zone* z = (struct local_zone*)calloc(1, sizeof(*z));
147 	if(!z) {
148 		return NULL;
149 	}
150 	z->node.key = z;
151 	z->dclass = dclass;
152 	z->type = t;
153 	z->name = nm;
154 	z->namelen = len;
155 	z->namelabs = labs;
156 	lock_rw_init(&z->lock);
157 	z->region = regional_create();
158 	if(!z->region) {
159 		free(z);
160 		return NULL;
161 	}
162 	rbtree_init(&z->data, &local_data_cmp);
163 	lock_protect(&z->lock, &z->parent, sizeof(*z)-sizeof(rbnode_t));
164 	/* also the zones->lock protects node, parent, name*, class */
165 	return z;
166 }
167 
168 /** enter a new zone with allocated dname returns with WRlock */
169 static struct local_zone*
170 lz_enter_zone_dname(struct local_zones* zones, uint8_t* nm, size_t len,
171 	int labs, enum localzone_type t, uint16_t c)
172 {
173 	struct local_zone* z = local_zone_create(nm, len, labs, t, c);
174 	if(!z) {
175 		free(nm);
176 		log_err("out of memory");
177 		return NULL;
178 	}
179 
180 	/* add to rbtree */
181 	lock_rw_wrlock(&zones->lock);
182 	lock_rw_wrlock(&z->lock);
183 	if(!rbtree_insert(&zones->ztree, &z->node)) {
184 		log_warn("duplicate local-zone");
185 		lock_rw_unlock(&z->lock);
186 		local_zone_delete(z);
187 		lock_rw_unlock(&zones->lock);
188 		return NULL;
189 	}
190 	lock_rw_unlock(&zones->lock);
191 	return z;
192 }
193 
194 /** enter a new zone */
195 static struct local_zone*
196 lz_enter_zone(struct local_zones* zones, const char* name, const char* type,
197 	uint16_t dclass)
198 {
199 	struct local_zone* z;
200 	enum localzone_type t;
201 	uint8_t* nm;
202 	size_t len;
203 	int labs;
204 	if(!parse_dname(name, &nm, &len, &labs)) {
205 		log_err("bad zone name %s %s", name, type);
206 		return NULL;
207 	}
208 	if(!local_zone_str2type(type, &t)) {
209 		log_err("bad lz_enter_zone type %s %s", name, type);
210 		free(nm);
211 		return NULL;
212 	}
213 	if(!(z=lz_enter_zone_dname(zones, nm, len, labs, t, dclass))) {
214 		log_err("could not enter zone %s %s", name, type);
215 		return NULL;
216 	}
217 	return z;
218 }
219 
220 /** return name and class and rdata of rr; parses string */
221 static int
222 get_rr_content(const char* str, uint8_t** nm, uint16_t* type,
223 	uint16_t* dclass, time_t* ttl, uint8_t* rr, size_t len,
224 	uint8_t** rdata, size_t* rdata_len)
225 {
226 	size_t dname_len = 0;
227 	int e = sldns_str2wire_rr_buf(str, rr, &len, &dname_len, 3600,
228 		NULL, 0, NULL, 0);
229 	if(e) {
230 		log_err("error parsing local-data at %d: '%s': %s",
231 			LDNS_WIREPARSE_OFFSET(e), str,
232 			sldns_get_errorstr_parse(e));
233 		return 0;
234 	}
235 	*nm = memdup(rr, dname_len);
236 	if(!*nm) {
237 		log_err("out of memory");
238 		return 0;
239 	}
240 	*dclass = sldns_wirerr_get_class(rr, len, dname_len);
241 	*type = sldns_wirerr_get_type(rr, len, dname_len);
242 	*ttl = (time_t)sldns_wirerr_get_ttl(rr, len, dname_len);
243 	*rdata = sldns_wirerr_get_rdatawl(rr, len, dname_len);
244 	*rdata_len = sldns_wirerr_get_rdatalen(rr, len, dname_len)+2;
245 	return 1;
246 }
247 
248 /** return name and class of rr; parses string */
249 static int
250 get_rr_nameclass(const char* str, uint8_t** nm, uint16_t* dclass)
251 {
252 	uint8_t rr[LDNS_RR_BUF_SIZE];
253 	size_t len = sizeof(rr), dname_len = 0;
254 	int s = sldns_str2wire_rr_buf(str, rr, &len, &dname_len, 3600,
255 		NULL, 0, NULL, 0);
256 	if(s != 0) {
257 		log_err("error parsing local-data at %d '%s': %s",
258 			LDNS_WIREPARSE_OFFSET(s), str,
259 			sldns_get_errorstr_parse(s));
260 		return 0;
261 	}
262 	*nm = memdup(rr, dname_len);
263 	*dclass = sldns_wirerr_get_class(rr, len, dname_len);
264 	if(!*nm) {
265 		log_err("out of memory");
266 		return 0;
267 	}
268 	return 1;
269 }
270 
271 /**
272  * Find an rrset in local data structure.
273  * @param data: local data domain name structure.
274  * @param type: type to look for (host order).
275  * @return rrset pointer or NULL if not found.
276  */
277 static struct local_rrset*
278 local_data_find_type(struct local_data* data, uint16_t type)
279 {
280 	struct local_rrset* p;
281 	type = htons(type);
282 	for(p = data->rrsets; p; p = p->next) {
283 		if(p->rrset->rk.type == type)
284 			return p;
285 	}
286 	return NULL;
287 }
288 
289 /** check for RR duplicates */
290 static int
291 rr_is_duplicate(struct packed_rrset_data* pd, uint8_t* rdata, size_t rdata_len)
292 {
293 	size_t i;
294 	for(i=0; i<pd->count; i++) {
295 		if(pd->rr_len[i] == rdata_len &&
296 			memcmp(pd->rr_data[i], rdata, rdata_len) == 0)
297 			return 1;
298 	}
299 	return 0;
300 }
301 
302 /** new local_rrset */
303 static struct local_rrset*
304 new_local_rrset(struct regional* region, struct local_data* node,
305 	uint16_t rrtype, uint16_t rrclass)
306 {
307 	struct packed_rrset_data* pd;
308 	struct local_rrset* rrset = (struct local_rrset*)
309 		regional_alloc_zero(region, sizeof(*rrset));
310 	if(!rrset) {
311 		log_err("out of memory");
312 		return NULL;
313 	}
314 	rrset->next = node->rrsets;
315 	node->rrsets = rrset;
316 	rrset->rrset = (struct ub_packed_rrset_key*)
317 		regional_alloc_zero(region, sizeof(*rrset->rrset));
318 	if(!rrset->rrset) {
319 		log_err("out of memory");
320 		return NULL;
321 	}
322 	rrset->rrset->entry.key = rrset->rrset;
323 	pd = (struct packed_rrset_data*)regional_alloc_zero(region,
324 		sizeof(*pd));
325 	if(!pd) {
326 		log_err("out of memory");
327 		return NULL;
328 	}
329 	pd->trust = rrset_trust_prim_noglue;
330 	pd->security = sec_status_insecure;
331 	rrset->rrset->entry.data = pd;
332 	rrset->rrset->rk.dname = node->name;
333 	rrset->rrset->rk.dname_len = node->namelen;
334 	rrset->rrset->rk.type = htons(rrtype);
335 	rrset->rrset->rk.rrset_class = htons(rrclass);
336 	return rrset;
337 }
338 
339 /** insert RR into RRset data structure; Wastes a couple of bytes */
340 static int
341 insert_rr(struct regional* region, struct packed_rrset_data* pd,
342 	uint8_t* rdata, size_t rdata_len, time_t ttl)
343 {
344 	size_t* oldlen = pd->rr_len;
345 	time_t* oldttl = pd->rr_ttl;
346 	uint8_t** olddata = pd->rr_data;
347 
348 	/* add RR to rrset */
349 	pd->count++;
350 	pd->rr_len = regional_alloc(region, sizeof(*pd->rr_len)*pd->count);
351 	pd->rr_ttl = regional_alloc(region, sizeof(*pd->rr_ttl)*pd->count);
352 	pd->rr_data = regional_alloc(region, sizeof(*pd->rr_data)*pd->count);
353 	if(!pd->rr_len || !pd->rr_ttl || !pd->rr_data) {
354 		log_err("out of memory");
355 		return 0;
356 	}
357 	if(pd->count > 1) {
358 		memcpy(pd->rr_len+1, oldlen,
359 			sizeof(*pd->rr_len)*(pd->count-1));
360 		memcpy(pd->rr_ttl+1, oldttl,
361 			sizeof(*pd->rr_ttl)*(pd->count-1));
362 		memcpy(pd->rr_data+1, olddata,
363 			sizeof(*pd->rr_data)*(pd->count-1));
364 	}
365 	pd->rr_len[0] = rdata_len;
366 	pd->rr_ttl[0] = ttl;
367 	pd->rr_data[0] = regional_alloc_init(region, rdata, rdata_len);
368 	if(!pd->rr_data[0]) {
369 		log_err("out of memory");
370 		return 0;
371 	}
372 	return 1;
373 }
374 
375 /** find a data node by exact name */
376 static struct local_data*
377 lz_find_node(struct local_zone* z, uint8_t* nm, size_t nmlen, int nmlabs)
378 {
379 	struct local_data key;
380 	key.node.key = &key;
381 	key.name = nm;
382 	key.namelen = nmlen;
383 	key.namelabs = nmlabs;
384 	return (struct local_data*)rbtree_search(&z->data, &key.node);
385 }
386 
387 /** find a node, create it if not and all its empty nonterminal parents */
388 static int
389 lz_find_create_node(struct local_zone* z, uint8_t* nm, size_t nmlen,
390 	int nmlabs, struct local_data** res)
391 {
392 	struct local_data* ld = lz_find_node(z, nm, nmlen, nmlabs);
393 	if(!ld) {
394 		/* create a domain name to store rr. */
395 		ld = (struct local_data*)regional_alloc_zero(z->region,
396 			sizeof(*ld));
397 		if(!ld) {
398 			log_err("out of memory adding local data");
399 			return 0;
400 		}
401 		ld->node.key = ld;
402 		ld->name = regional_alloc_init(z->region, nm, nmlen);
403 		if(!ld->name) {
404 			log_err("out of memory");
405 			return 0;
406 		}
407 		ld->namelen = nmlen;
408 		ld->namelabs = nmlabs;
409 		if(!rbtree_insert(&z->data, &ld->node)) {
410 			log_assert(0); /* duplicate name */
411 		}
412 		/* see if empty nonterminals need to be created */
413 		if(nmlabs > z->namelabs) {
414 			dname_remove_label(&nm, &nmlen);
415 			if(!lz_find_create_node(z, nm, nmlen, nmlabs-1, res))
416 				return 0;
417 		}
418 	}
419 	*res = ld;
420 	return 1;
421 }
422 
423 /** enter data RR into auth zone */
424 static int
425 lz_enter_rr_into_zone(struct local_zone* z, const char* rrstr)
426 {
427 	uint8_t* nm;
428 	size_t nmlen;
429 	int nmlabs;
430 	struct local_data* node;
431 	struct local_rrset* rrset;
432 	struct packed_rrset_data* pd;
433 	uint16_t rrtype = 0, rrclass = 0;
434 	time_t ttl = 0;
435 	uint8_t rr[LDNS_RR_BUF_SIZE];
436 	uint8_t* rdata;
437 	size_t rdata_len;
438 	if(!get_rr_content(rrstr, &nm, &rrtype, &rrclass, &ttl, rr, sizeof(rr),
439 		&rdata, &rdata_len)) {
440 		log_err("bad local-data: %s", rrstr);
441 		return 0;
442 	}
443 	log_assert(z->dclass == rrclass);
444 	if(z->type == local_zone_redirect &&
445 		query_dname_compare(z->name, nm) != 0) {
446 		log_err("local-data in redirect zone must reside at top of zone"
447 			", not at %s", rrstr);
448 		free(nm);
449 		return 0;
450 	}
451 	nmlabs = dname_count_size_labels(nm, &nmlen);
452 	if(!lz_find_create_node(z, nm, nmlen, nmlabs, &node)) {
453 		free(nm);
454 		return 0;
455 	}
456 	log_assert(node);
457 	free(nm);
458 
459 	rrset = local_data_find_type(node, rrtype);
460 	if(!rrset) {
461 		rrset = new_local_rrset(z->region, node, rrtype, rrclass);
462 		if(!rrset)
463 			return 0;
464 		if(query_dname_compare(node->name, z->name) == 0) {
465 			if(rrtype == LDNS_RR_TYPE_NSEC)
466 			  rrset->rrset->rk.flags = PACKED_RRSET_NSEC_AT_APEX;
467 			if(rrtype == LDNS_RR_TYPE_SOA)
468 				z->soa = rrset->rrset;
469 		}
470 	}
471 	pd = (struct packed_rrset_data*)rrset->rrset->entry.data;
472 	log_assert(rrset && pd);
473 
474 	/* check for duplicate RR */
475 	if(rr_is_duplicate(pd, rdata, rdata_len)) {
476 		verbose(VERB_ALGO, "ignoring duplicate RR: %s", rrstr);
477 		return 1;
478 	}
479 	return insert_rr(z->region, pd, rdata, rdata_len, ttl);
480 }
481 
482 /** enter a data RR into auth data; a zone for it must exist */
483 static int
484 lz_enter_rr_str(struct local_zones* zones, const char* rr)
485 {
486 	uint8_t* rr_name;
487 	uint16_t rr_class;
488 	size_t len;
489 	int labs;
490 	struct local_zone* z;
491 	int r;
492 	if(!get_rr_nameclass(rr, &rr_name, &rr_class)) {
493 		log_err("bad rr %s", rr);
494 		return 0;
495 	}
496 	labs = dname_count_size_labels(rr_name, &len);
497 	lock_rw_rdlock(&zones->lock);
498 	z = local_zones_lookup(zones, rr_name, len, labs, rr_class);
499 	if(!z) {
500 		lock_rw_unlock(&zones->lock);
501 		fatal_exit("internal error: no zone for rr %s", rr);
502 	}
503 	lock_rw_wrlock(&z->lock);
504 	lock_rw_unlock(&zones->lock);
505 	free(rr_name);
506 	r = lz_enter_rr_into_zone(z, rr);
507 	lock_rw_unlock(&z->lock);
508 	return r;
509 }
510 
511 /** enter tagstring into zone */
512 static int
513 lz_enter_zone_tag(struct local_zones* zones, char* zname, uint8_t* list,
514 	size_t len, uint16_t rr_class)
515 {
516 	uint8_t dname[LDNS_MAX_DOMAINLEN+1];
517 	size_t dname_len = sizeof(dname);
518 	int dname_labs, r = 0;
519 	struct local_zone* z;
520 
521 	if(sldns_str2wire_dname_buf(zname, dname, &dname_len) != 0) {
522 		log_err("cannot parse zone name in local-zone-tag: %s", zname);
523 		return 0;
524 	}
525 	dname_labs = dname_count_labels(dname);
526 
527 	lock_rw_rdlock(&zones->lock);
528 	z = local_zones_lookup(zones, dname, dname_len, dname_labs, rr_class);
529 	if(!z) {
530 		lock_rw_unlock(&zones->lock);
531 		log_err("no local-zone for tag %s", zname);
532 		return 0;
533 	}
534 	lock_rw_wrlock(&z->lock);
535 	lock_rw_unlock(&zones->lock);
536 	free(z->taglist);
537 	z->taglist = memdup(list, len);
538 	z->taglen = len;
539 	if(z->taglist)
540 		r = 1;
541 	lock_rw_unlock(&z->lock);
542 	return r;
543 }
544 
545 /** parse local-zone: statements */
546 static int
547 lz_enter_zones(struct local_zones* zones, struct config_file* cfg)
548 {
549 	struct config_str2list* p;
550 	struct local_zone* z;
551 	for(p = cfg->local_zones; p; p = p->next) {
552 		if(!(z=lz_enter_zone(zones, p->str, p->str2,
553 			LDNS_RR_CLASS_IN)))
554 			return 0;
555 		lock_rw_unlock(&z->lock);
556 	}
557 	return 1;
558 }
559 
560 /** lookup a zone in rbtree; exact match only; SLOW due to parse */
561 static int
562 lz_exists(struct local_zones* zones, const char* name)
563 {
564 	struct local_zone z;
565 	z.node.key = &z;
566 	z.dclass = LDNS_RR_CLASS_IN;
567 	if(!parse_dname(name, &z.name, &z.namelen, &z.namelabs)) {
568 		log_err("bad name %s", name);
569 		return 0;
570 	}
571 	lock_rw_rdlock(&zones->lock);
572 	if(rbtree_search(&zones->ztree, &z.node)) {
573 		lock_rw_unlock(&zones->lock);
574 		free(z.name);
575 		return 1;
576 	}
577 	lock_rw_unlock(&zones->lock);
578 	free(z.name);
579 	return 0;
580 }
581 
582 /** lookup a zone in cfg->nodefault list */
583 static int
584 lz_nodefault(struct config_file* cfg, const char* name)
585 {
586 	struct config_strlist* p;
587 	size_t len = strlen(name);
588 	if(len == 0) return 0;
589 	if(name[len-1] == '.') len--;
590 
591 	for(p = cfg->local_zones_nodefault; p; p = p->next) {
592 		/* compare zone name, lowercase, compare without ending . */
593 		if(strncasecmp(p->str, name, len) == 0 &&
594 			(strlen(p->str) == len || (strlen(p->str)==len+1 &&
595 			p->str[len] == '.')))
596 			return 1;
597 	}
598 	return 0;
599 }
600 
601 /** enter AS112 default zone */
602 static int
603 add_as112_default(struct local_zones* zones, struct config_file* cfg,
604         const char* name)
605 {
606 	struct local_zone* z;
607 	char str[1024]; /* known long enough */
608 	if(lz_exists(zones, name) || lz_nodefault(cfg, name))
609 		return 1; /* do not enter default content */
610 	if(!(z=lz_enter_zone(zones, name, "static", LDNS_RR_CLASS_IN)))
611 		return 0;
612 	snprintf(str, sizeof(str), "%s 10800 IN SOA localhost. "
613 		"nobody.invalid. 1 3600 1200 604800 10800", name);
614 	if(!lz_enter_rr_into_zone(z, str)) {
615 		lock_rw_unlock(&z->lock);
616 		return 0;
617 	}
618 	snprintf(str, sizeof(str), "%s 10800 IN NS localhost. ", name);
619 	if(!lz_enter_rr_into_zone(z, str)) {
620 		lock_rw_unlock(&z->lock);
621 		return 0;
622 	}
623 	lock_rw_unlock(&z->lock);
624 	return 1;
625 }
626 
627 /** enter default zones */
628 static int
629 lz_enter_defaults(struct local_zones* zones, struct config_file* cfg)
630 {
631 	struct local_zone* z;
632 	const char** zstr;
633 
634 	/* this list of zones is from RFC 6303 and RFC 7686 */
635 
636 	/* block localhost level zones first, then onion and later the LAN zones */
637 
638 	/* localhost. zone */
639 	if(!lz_exists(zones, "localhost.") &&
640 		!lz_nodefault(cfg, "localhost.")) {
641 		if(!(z=lz_enter_zone(zones, "localhost.", "static",
642 			LDNS_RR_CLASS_IN)) ||
643 		   !lz_enter_rr_into_zone(z,
644 			"localhost. 10800 IN NS localhost.") ||
645 		   !lz_enter_rr_into_zone(z,
646 			"localhost. 10800 IN SOA localhost. nobody.invalid. "
647 			"1 3600 1200 604800 10800") ||
648 		   !lz_enter_rr_into_zone(z,
649 			"localhost. 10800 IN A 127.0.0.1") ||
650 		   !lz_enter_rr_into_zone(z,
651 			"localhost. 10800 IN AAAA ::1")) {
652 			log_err("out of memory adding default zone");
653 			if(z) { lock_rw_unlock(&z->lock); }
654 			return 0;
655 		}
656 		lock_rw_unlock(&z->lock);
657 	}
658 	/* reverse ip4 zone */
659 	if(!lz_exists(zones, "127.in-addr.arpa.") &&
660 		!lz_nodefault(cfg, "127.in-addr.arpa.")) {
661 		if(!(z=lz_enter_zone(zones, "127.in-addr.arpa.", "static",
662 			LDNS_RR_CLASS_IN)) ||
663 		   !lz_enter_rr_into_zone(z,
664 			"127.in-addr.arpa. 10800 IN NS localhost.") ||
665 		   !lz_enter_rr_into_zone(z,
666 			"127.in-addr.arpa. 10800 IN SOA localhost. "
667 			"nobody.invalid. 1 3600 1200 604800 10800") ||
668 		   !lz_enter_rr_into_zone(z,
669 			"1.0.0.127.in-addr.arpa. 10800 IN PTR localhost.")) {
670 			log_err("out of memory adding default zone");
671 			if(z) { lock_rw_unlock(&z->lock); }
672 			return 0;
673 		}
674 		lock_rw_unlock(&z->lock);
675 	}
676 	/* reverse ip6 zone */
677 	if(!lz_exists(zones, "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa.") &&
678 		!lz_nodefault(cfg, "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa.")) {
679 		if(!(z=lz_enter_zone(zones, "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa.", "static",
680 			LDNS_RR_CLASS_IN)) ||
681 		   !lz_enter_rr_into_zone(z,
682 			"1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa. 10800 IN NS localhost.") ||
683 		   !lz_enter_rr_into_zone(z,
684 			"1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa. 10800 IN SOA localhost. "
685 			"nobody.invalid. 1 3600 1200 604800 10800") ||
686 		   !lz_enter_rr_into_zone(z,
687 			"1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa. 10800 IN PTR localhost.")) {
688 			log_err("out of memory adding default zone");
689 			if(z) { lock_rw_unlock(&z->lock); }
690 			return 0;
691 		}
692 		lock_rw_unlock(&z->lock);
693 	}
694 	/* onion. zone (RFC 7686) */
695 	if(!lz_exists(zones, "onion.") &&
696 		!lz_nodefault(cfg, "onion.")) {
697 		if(!(z=lz_enter_zone(zones, "onion.", "static",
698 			LDNS_RR_CLASS_IN)) ||
699 		   !lz_enter_rr_into_zone(z,
700 			"onion. 10800 IN NS localhost.") ||
701 		   !lz_enter_rr_into_zone(z,
702 			"onion. 10800 IN SOA localhost. nobody.invalid. "
703 			"1 3600 1200 604800 10800")) {
704 			log_err("out of memory adding default zone");
705 			if(z) { lock_rw_unlock(&z->lock); }
706 			return 0;
707 		}
708 		lock_rw_unlock(&z->lock);
709 	}
710 
711 	/* block AS112 zones, unless asked not to */
712 	if(!cfg->unblock_lan_zones) {
713 		for(zstr = as112_zones; *zstr; zstr++) {
714 			if(!add_as112_default(zones, cfg, *zstr)) {
715 				log_err("out of memory adding default zone");
716 				return 0;
717 			}
718 		}
719 	}
720 	return 1;
721 }
722 
723 /** setup parent pointers, so that a lookup can be done for closest match */
724 static void
725 init_parents(struct local_zones* zones)
726 {
727         struct local_zone* node, *prev = NULL, *p;
728         int m;
729 	lock_rw_wrlock(&zones->lock);
730         RBTREE_FOR(node, struct local_zone*, &zones->ztree) {
731 		lock_rw_wrlock(&node->lock);
732                 node->parent = NULL;
733                 if(!prev || prev->dclass != node->dclass) {
734                         prev = node;
735 			lock_rw_unlock(&node->lock);
736                         continue;
737                 }
738                 (void)dname_lab_cmp(prev->name, prev->namelabs, node->name,
739                         node->namelabs, &m); /* we know prev is smaller */
740                 /* sort order like: . com. bla.com. zwb.com. net. */
741                 /* find the previous, or parent-parent-parent */
742                 for(p = prev; p; p = p->parent)
743                         /* looking for name with few labels, a parent */
744                         if(p->namelabs <= m) {
745                                 /* ==: since prev matched m, this is closest*/
746                                 /* <: prev matches more, but is not a parent,
747                                  * this one is a (grand)parent */
748                                 node->parent = p;
749                                 break;
750                         }
751                 prev = node;
752 		lock_rw_unlock(&node->lock);
753         }
754 	lock_rw_unlock(&zones->lock);
755 }
756 
757 /** enter implicit transparent zone for local-data: without local-zone: */
758 static int
759 lz_setup_implicit(struct local_zones* zones, struct config_file* cfg)
760 {
761 	/* walk over all items that have no parent zone and find
762 	 * the name that covers them all (could be the root) and
763 	 * add that as a transparent zone */
764 	struct config_strlist* p;
765 	int have_name = 0;
766 	int have_other_classes = 0;
767 	uint16_t dclass = 0;
768 	uint8_t* nm = 0;
769 	size_t nmlen = 0;
770 	int nmlabs = 0;
771 	int match = 0; /* number of labels match count */
772 
773 	init_parents(zones); /* to enable local_zones_lookup() */
774 	for(p = cfg->local_data; p; p = p->next) {
775 		uint8_t* rr_name;
776 		uint16_t rr_class;
777 		size_t len;
778 		int labs;
779 		if(!get_rr_nameclass(p->str, &rr_name, &rr_class)) {
780 			log_err("Bad local-data RR %s", p->str);
781 			return 0;
782 		}
783 		labs = dname_count_size_labels(rr_name, &len);
784 		lock_rw_rdlock(&zones->lock);
785 		if(!local_zones_lookup(zones, rr_name, len, labs, rr_class)) {
786 			if(!have_name) {
787 				dclass = rr_class;
788 				nm = rr_name;
789 				nmlen = len;
790 				nmlabs = labs;
791 				match = labs;
792 				have_name = 1;
793 			} else {
794 				int m;
795 				if(rr_class != dclass) {
796 					/* process other classes later */
797 					free(rr_name);
798 					have_other_classes = 1;
799 					lock_rw_unlock(&zones->lock);
800 					continue;
801 				}
802 				/* find smallest shared topdomain */
803 				(void)dname_lab_cmp(nm, nmlabs,
804 					rr_name, labs, &m);
805 				free(rr_name);
806 				if(m < match)
807 					match = m;
808 			}
809 		} else free(rr_name);
810 		lock_rw_unlock(&zones->lock);
811 	}
812 	if(have_name) {
813 		uint8_t* n2;
814 		struct local_zone* z;
815 		/* allocate zone of smallest shared topdomain to contain em */
816 		n2 = nm;
817 		dname_remove_labels(&n2, &nmlen, nmlabs - match);
818 		n2 = memdup(n2, nmlen);
819 		free(nm);
820 		if(!n2) {
821 			log_err("out of memory");
822 			return 0;
823 		}
824 		log_nametypeclass(VERB_ALGO, "implicit transparent local-zone",
825 			n2, 0, dclass);
826 		if(!(z=lz_enter_zone_dname(zones, n2, nmlen, match,
827 			local_zone_transparent, dclass))) {
828 			return 0;
829 		}
830 		lock_rw_unlock(&z->lock);
831 	}
832 	if(have_other_classes) {
833 		/* restart to setup other class */
834 		return lz_setup_implicit(zones, cfg);
835 	}
836 	return 1;
837 }
838 
839 /** enter local-zone-tag info */
840 static int
841 lz_enter_zone_tags(struct local_zones* zones, struct config_file* cfg)
842 {
843 	struct config_strbytelist* p;
844 	int c = 0;
845 	for(p = cfg->local_zone_tags; p; p = p->next) {
846 		if(!lz_enter_zone_tag(zones, p->str, p->str2, p->str2len,
847 			LDNS_RR_CLASS_IN))
848 			return 0;
849 		c++;
850 	}
851 	if(c) verbose(VERB_ALGO, "applied tags to %d local zones", c);
852 	return 1;
853 }
854 
855 /** enter auth data */
856 static int
857 lz_enter_data(struct local_zones* zones, struct config_file* cfg)
858 {
859 	struct config_strlist* p;
860 	for(p = cfg->local_data; p; p = p->next) {
861 		if(!lz_enter_rr_str(zones, p->str))
862 			return 0;
863 	}
864 	return 1;
865 }
866 
867 /** free memory from config */
868 static void
869 lz_freeup_cfg(struct config_file* cfg)
870 {
871 	config_deldblstrlist(cfg->local_zones);
872 	cfg->local_zones = NULL;
873 	config_delstrlist(cfg->local_zones_nodefault);
874 	cfg->local_zones_nodefault = NULL;
875 	config_delstrlist(cfg->local_data);
876 	cfg->local_data = NULL;
877 }
878 
879 int
880 local_zones_apply_cfg(struct local_zones* zones, struct config_file* cfg)
881 {
882 	/* create zones from zone statements. */
883 	if(!lz_enter_zones(zones, cfg)) {
884 		return 0;
885 	}
886 	/* apply default zones+content (unless disabled, or overridden) */
887 	if(!lz_enter_defaults(zones, cfg)) {
888 		return 0;
889 	}
890 	/* create implicit transparent zone from data. */
891 	if(!lz_setup_implicit(zones, cfg)) {
892 		return 0;
893 	}
894 
895 	/* setup parent ptrs for lookup during data entry */
896 	init_parents(zones);
897 	/* insert local zone tags */
898 	if(!lz_enter_zone_tags(zones, cfg)) {
899 		return 0;
900 	}
901 	/* insert local data */
902 	if(!lz_enter_data(zones, cfg)) {
903 		return 0;
904 	}
905 	/* freeup memory from cfg struct. */
906 	lz_freeup_cfg(cfg);
907 	return 1;
908 }
909 
910 struct local_zone*
911 local_zones_lookup(struct local_zones* zones,
912         uint8_t* name, size_t len, int labs, uint16_t dclass)
913 {
914 	rbnode_t* res = NULL;
915 	struct local_zone *result;
916 	struct local_zone key;
917 	key.node.key = &key;
918 	key.dclass = dclass;
919 	key.name = name;
920 	key.namelen = len;
921 	key.namelabs = labs;
922 	if(rbtree_find_less_equal(&zones->ztree, &key, &res)) {
923 		/* exact */
924 		return (struct local_zone*)res;
925 	} else {
926 	        /* smaller element (or no element) */
927                 int m;
928                 result = (struct local_zone*)res;
929                 if(!result || result->dclass != dclass)
930                         return NULL;
931                 /* count number of labels matched */
932                 (void)dname_lab_cmp(result->name, result->namelabs, key.name,
933                         key.namelabs, &m);
934                 while(result) { /* go up until qname is subdomain of zone */
935                         if(result->namelabs <= m)
936                                 break;
937                         result = result->parent;
938                 }
939 		return result;
940 	}
941 }
942 
943 struct local_zone*
944 local_zones_find(struct local_zones* zones,
945         uint8_t* name, size_t len, int labs, uint16_t dclass)
946 {
947 	struct local_zone key;
948 	key.node.key = &key;
949 	key.dclass = dclass;
950 	key.name = name;
951 	key.namelen = len;
952 	key.namelabs = labs;
953 	/* exact */
954 	return (struct local_zone*)rbtree_search(&zones->ztree, &key);
955 }
956 
957 /** print all RRsets in local zone */
958 static void
959 local_zone_out(struct local_zone* z)
960 {
961 	struct local_data* d;
962 	struct local_rrset* p;
963 	RBTREE_FOR(d, struct local_data*, &z->data) {
964 		for(p = d->rrsets; p; p = p->next) {
965 			log_nametypeclass(0, "rrset", d->name,
966 				ntohs(p->rrset->rk.type),
967 				ntohs(p->rrset->rk.rrset_class));
968 		}
969 	}
970 }
971 
972 void local_zones_print(struct local_zones* zones)
973 {
974 	struct local_zone* z;
975 	lock_rw_rdlock(&zones->lock);
976 	log_info("number of auth zones %u", (unsigned)zones->ztree.count);
977 	RBTREE_FOR(z, struct local_zone*, &zones->ztree) {
978 		lock_rw_rdlock(&z->lock);
979 		switch(z->type) {
980 		case local_zone_deny:
981 			log_nametypeclass(0, "deny zone",
982 				z->name, 0, z->dclass);
983 			break;
984 		case local_zone_refuse:
985 			log_nametypeclass(0, "refuse zone",
986 				z->name, 0, z->dclass);
987 			break;
988 		case local_zone_redirect:
989 			log_nametypeclass(0, "redirect zone",
990 				z->name, 0, z->dclass);
991 			break;
992 		case local_zone_transparent:
993 			log_nametypeclass(0, "transparent zone",
994 				z->name, 0, z->dclass);
995 			break;
996 		case local_zone_typetransparent:
997 			log_nametypeclass(0, "typetransparent zone",
998 				z->name, 0, z->dclass);
999 			break;
1000 		case local_zone_static:
1001 			log_nametypeclass(0, "static zone",
1002 				z->name, 0, z->dclass);
1003 			break;
1004 		case local_zone_inform:
1005 			log_nametypeclass(0, "inform zone",
1006 				z->name, 0, z->dclass);
1007 			break;
1008 		case local_zone_inform_deny:
1009 			log_nametypeclass(0, "inform_deny zone",
1010 				z->name, 0, z->dclass);
1011 			break;
1012 		default:
1013 			log_nametypeclass(0, "badtyped zone",
1014 				z->name, 0, z->dclass);
1015 			break;
1016 		}
1017 		local_zone_out(z);
1018 		lock_rw_unlock(&z->lock);
1019 	}
1020 	lock_rw_unlock(&zones->lock);
1021 }
1022 
1023 /** encode answer consisting of 1 rrset */
1024 static int
1025 local_encode(struct query_info* qinfo, struct edns_data* edns,
1026 	sldns_buffer* buf, struct regional* temp,
1027 	struct ub_packed_rrset_key* rrset, int ansec, int rcode)
1028 {
1029 	struct reply_info rep;
1030 	uint16_t udpsize;
1031 	/* make answer with time=0 for fixed TTL values */
1032 	memset(&rep, 0, sizeof(rep));
1033 	rep.flags = (uint16_t)((BIT_QR | BIT_AA | BIT_RA) | rcode);
1034 	rep.qdcount = 1;
1035 	if(ansec)
1036 		rep.an_numrrsets = 1;
1037 	else	rep.ns_numrrsets = 1;
1038 	rep.rrset_count = 1;
1039 	rep.rrsets = &rrset;
1040 	udpsize = edns->udp_size;
1041 	edns->edns_version = EDNS_ADVERTISED_VERSION;
1042 	edns->udp_size = EDNS_ADVERTISED_SIZE;
1043 	edns->ext_rcode = 0;
1044 	edns->bits &= EDNS_DO;
1045 	if(!edns_opt_inplace_reply(edns, temp) ||
1046 	   !reply_info_answer_encode(qinfo, &rep,
1047 		*(uint16_t*)sldns_buffer_begin(buf),
1048 		sldns_buffer_read_u16_at(buf, 2),
1049 		buf, 0, 0, temp, udpsize, edns,
1050 		(int)(edns->bits&EDNS_DO), 0))
1051 		error_encode(buf, (LDNS_RCODE_SERVFAIL|BIT_AA), qinfo,
1052 			*(uint16_t*)sldns_buffer_begin(buf),
1053 		       sldns_buffer_read_u16_at(buf, 2), edns);
1054 	return 1;
1055 }
1056 
1057 /** answer local data match */
1058 static int
1059 local_data_answer(struct local_zone* z, struct query_info* qinfo,
1060 	struct edns_data* edns, sldns_buffer* buf, struct regional* temp,
1061 	int labs, struct local_data** ldp)
1062 {
1063 	struct local_data key;
1064 	struct local_data* ld;
1065 	struct local_rrset* lr;
1066 	key.node.key = &key;
1067 	key.name = qinfo->qname;
1068 	key.namelen = qinfo->qname_len;
1069 	key.namelabs = labs;
1070 	if(z->type == local_zone_redirect) {
1071 		key.name = z->name;
1072 		key.namelen = z->namelen;
1073 		key.namelabs = z->namelabs;
1074 	}
1075 	ld = (struct local_data*)rbtree_search(&z->data, &key.node);
1076 	*ldp = ld;
1077 	if(!ld) {
1078 		return 0;
1079 	}
1080 	lr = local_data_find_type(ld, qinfo->qtype);
1081 	if(!lr)
1082 		return 0;
1083 	if(z->type == local_zone_redirect) {
1084 		/* convert rrset name to query name; like a wildcard */
1085 		struct ub_packed_rrset_key r = *lr->rrset;
1086 		r.rk.dname = qinfo->qname;
1087 		r.rk.dname_len = qinfo->qname_len;
1088 		return local_encode(qinfo, edns, buf, temp, &r, 1,
1089 			LDNS_RCODE_NOERROR);
1090 	}
1091 	return local_encode(qinfo, edns, buf, temp, lr->rrset, 1,
1092 		LDNS_RCODE_NOERROR);
1093 }
1094 
1095 /**
1096  * answer in case where no exact match is found
1097  * @param z: zone for query
1098  * @param qinfo: query
1099  * @param edns: edns from query
1100  * @param buf: buffer for answer.
1101  * @param temp: temp region for encoding
1102  * @param ld: local data, if NULL, no such name exists in localdata.
1103  * @return 1 if a reply is to be sent, 0 if not.
1104  */
1105 static int
1106 lz_zone_answer(struct local_zone* z, struct query_info* qinfo,
1107 	struct edns_data* edns, sldns_buffer* buf, struct regional* temp,
1108 	struct local_data* ld)
1109 {
1110 	if(z->type == local_zone_deny || z->type == local_zone_inform_deny) {
1111 		/** no reply at all, signal caller by clearing buffer. */
1112 		sldns_buffer_clear(buf);
1113 		sldns_buffer_flip(buf);
1114 		return 1;
1115 	} else if(z->type == local_zone_refuse) {
1116 		error_encode(buf, (LDNS_RCODE_REFUSED|BIT_AA), qinfo,
1117 			*(uint16_t*)sldns_buffer_begin(buf),
1118 		       sldns_buffer_read_u16_at(buf, 2), edns);
1119 		return 1;
1120 	} else if(z->type == local_zone_static ||
1121 		z->type == local_zone_redirect) {
1122 		/* for static, reply nodata or nxdomain
1123 		 * for redirect, reply nodata */
1124 		/* no additional section processing,
1125 		 * cname, dname or wildcard processing,
1126 		 * or using closest match for NSEC.
1127 		 * or using closest match for returning delegation downwards
1128 		 */
1129 		int rcode = ld?LDNS_RCODE_NOERROR:LDNS_RCODE_NXDOMAIN;
1130 		if(z->soa)
1131 			return local_encode(qinfo, edns, buf, temp,
1132 				z->soa, 0, rcode);
1133 		error_encode(buf, (rcode|BIT_AA), qinfo,
1134 			*(uint16_t*)sldns_buffer_begin(buf),
1135 			sldns_buffer_read_u16_at(buf, 2), edns);
1136 		return 1;
1137 	} else if(z->type == local_zone_typetransparent) {
1138 		/* no NODATA or NXDOMAINS for this zone type */
1139 		return 0;
1140 	}
1141 	/* else z->type == local_zone_transparent */
1142 
1143 	/* if the zone is transparent and the name exists, but the type
1144 	 * does not, then we should make this noerror/nodata */
1145 	if(ld && ld->rrsets) {
1146 		int rcode = LDNS_RCODE_NOERROR;
1147 		if(z->soa)
1148 			return local_encode(qinfo, edns, buf, temp,
1149 				z->soa, 0, rcode);
1150 		error_encode(buf, (rcode|BIT_AA), qinfo,
1151 			*(uint16_t*)sldns_buffer_begin(buf),
1152 			sldns_buffer_read_u16_at(buf, 2), edns);
1153 		return 1;
1154 	}
1155 
1156 	/* stop here, and resolve further on */
1157 	return 0;
1158 }
1159 
1160 /** print log information for an inform zone query */
1161 static void
1162 lz_inform_print(struct local_zone* z, struct query_info* qinfo,
1163 	struct comm_reply* repinfo)
1164 {
1165 	char ip[128], txt[512];
1166 	char zname[LDNS_MAX_DOMAINLEN+1];
1167 	uint16_t port = ntohs(((struct sockaddr_in*)&repinfo->addr)->sin_port);
1168 	dname_str(z->name, zname);
1169 	addr_to_str(&repinfo->addr, repinfo->addrlen, ip, sizeof(ip));
1170 	snprintf(txt, sizeof(txt), "%s inform %s@%u", zname, ip,
1171 		(unsigned)port);
1172 	log_nametypeclass(0, txt, qinfo->qname, qinfo->qtype, qinfo->qclass);
1173 }
1174 
1175 int
1176 local_zones_answer(struct local_zones* zones, struct query_info* qinfo,
1177 	struct edns_data* edns, sldns_buffer* buf, struct regional* temp,
1178 	struct comm_reply* repinfo)
1179 {
1180 	/* see if query is covered by a zone,
1181 	 * 	if so:	- try to match (exact) local data
1182 	 * 		- look at zone type for negative response. */
1183 	int labs = dname_count_labels(qinfo->qname);
1184 	struct local_data* ld;
1185 	struct local_zone* z;
1186 	int r;
1187 	lock_rw_rdlock(&zones->lock);
1188 	z = local_zones_lookup(zones, qinfo->qname,
1189 		qinfo->qname_len, labs, qinfo->qclass);
1190 	if(!z) {
1191 		lock_rw_unlock(&zones->lock);
1192 		return 0;
1193 	}
1194 	lock_rw_rdlock(&z->lock);
1195 	lock_rw_unlock(&zones->lock);
1196 
1197 	if((z->type == local_zone_inform || z->type == local_zone_inform_deny)
1198 		&& repinfo)
1199 		lz_inform_print(z, qinfo, repinfo);
1200 
1201 	if(local_data_answer(z, qinfo, edns, buf, temp, labs, &ld)) {
1202 		lock_rw_unlock(&z->lock);
1203 		return 1;
1204 	}
1205 	r = lz_zone_answer(z, qinfo, edns, buf, temp, ld);
1206 	lock_rw_unlock(&z->lock);
1207 	return r;
1208 }
1209 
1210 const char* local_zone_type2str(enum localzone_type t)
1211 {
1212 	switch(t) {
1213 		case local_zone_deny: return "deny";
1214 		case local_zone_refuse: return "refuse";
1215 		case local_zone_redirect: return "redirect";
1216 		case local_zone_transparent: return "transparent";
1217 		case local_zone_typetransparent: return "typetransparent";
1218 		case local_zone_static: return "static";
1219 		case local_zone_nodefault: return "nodefault";
1220 		case local_zone_inform: return "inform";
1221 		case local_zone_inform_deny: return "inform_deny";
1222 	}
1223 	return "badtyped";
1224 }
1225 
1226 int local_zone_str2type(const char* type, enum localzone_type* t)
1227 {
1228 	if(strcmp(type, "deny") == 0)
1229 		*t = local_zone_deny;
1230 	else if(strcmp(type, "refuse") == 0)
1231 		*t = local_zone_refuse;
1232 	else if(strcmp(type, "static") == 0)
1233 		*t = local_zone_static;
1234 	else if(strcmp(type, "transparent") == 0)
1235 		*t = local_zone_transparent;
1236 	else if(strcmp(type, "typetransparent") == 0)
1237 		*t = local_zone_typetransparent;
1238 	else if(strcmp(type, "redirect") == 0)
1239 		*t = local_zone_redirect;
1240 	else if(strcmp(type, "inform") == 0)
1241 		*t = local_zone_inform;
1242 	else if(strcmp(type, "inform_deny") == 0)
1243 		*t = local_zone_inform_deny;
1244 	else return 0;
1245 	return 1;
1246 }
1247 
1248 /** iterate over the kiddies of the given name and set their parent ptr */
1249 static void
1250 set_kiddo_parents(struct local_zone* z, struct local_zone* match,
1251 	struct local_zone* newp)
1252 {
1253 	/* both zones and z are locked already */
1254 	/* in the sorted rbtree, the kiddies of z are located after z */
1255 	/* z must be present in the tree */
1256 	struct local_zone* p = z;
1257 	p = (struct local_zone*)rbtree_next(&p->node);
1258 	while(p!=(struct local_zone*)RBTREE_NULL &&
1259 		p->dclass == z->dclass && dname_strict_subdomain(p->name,
1260 		p->namelabs, z->name, z->namelabs)) {
1261 		/* update parent ptr */
1262 		/* only when matches with existing parent pointer, so that
1263 		 * deeper child structures are not touched, i.e.
1264 		 * update of x, and a.x, b.x, f.b.x, g.b.x, c.x, y
1265 		 * gets to update a.x, b.x and c.x */
1266 		lock_rw_wrlock(&p->lock);
1267 		if(p->parent == match)
1268 			p->parent = newp;
1269 		lock_rw_unlock(&p->lock);
1270 		p = (struct local_zone*)rbtree_next(&p->node);
1271 	}
1272 }
1273 
1274 struct local_zone* local_zones_add_zone(struct local_zones* zones,
1275 	uint8_t* name, size_t len, int labs, uint16_t dclass,
1276 	enum localzone_type tp)
1277 {
1278 	/* create */
1279 	struct local_zone* z = local_zone_create(name, len, labs, tp, dclass);
1280 	if(!z) {
1281 		free(name);
1282 		return NULL;
1283 	}
1284 	lock_rw_wrlock(&z->lock);
1285 
1286 	/* find the closest parent */
1287 	z->parent = local_zones_find(zones, name, len, labs, dclass);
1288 
1289 	/* insert into the tree */
1290 	if(!rbtree_insert(&zones->ztree, &z->node)) {
1291 		/* duplicate entry! */
1292 		lock_rw_unlock(&z->lock);
1293 		local_zone_delete(z);
1294 		log_err("internal: duplicate entry in local_zones_add_zone");
1295 		return NULL;
1296 	}
1297 
1298 	/* set parent pointers right */
1299 	set_kiddo_parents(z, z->parent, z);
1300 
1301 	lock_rw_unlock(&z->lock);
1302 	return z;
1303 }
1304 
1305 void local_zones_del_zone(struct local_zones* zones, struct local_zone* z)
1306 {
1307 	/* fix up parents in tree */
1308 	lock_rw_wrlock(&z->lock);
1309 	set_kiddo_parents(z, z, z->parent);
1310 
1311 	/* remove from tree */
1312 	(void)rbtree_delete(&zones->ztree, z);
1313 
1314 	/* delete the zone */
1315 	lock_rw_unlock(&z->lock);
1316 	local_zone_delete(z);
1317 }
1318 
1319 int
1320 local_zones_add_RR(struct local_zones* zones, const char* rr)
1321 {
1322 	uint8_t* rr_name;
1323 	uint16_t rr_class;
1324 	size_t len;
1325 	int labs;
1326 	struct local_zone* z;
1327 	int r;
1328 	if(!get_rr_nameclass(rr, &rr_name, &rr_class)) {
1329 		return 0;
1330 	}
1331 	labs = dname_count_size_labels(rr_name, &len);
1332 	/* could first try readlock then get writelock if zone does not exist,
1333 	 * but we do not add enough RRs (from multiple threads) to optimize */
1334 	lock_rw_wrlock(&zones->lock);
1335 	z = local_zones_lookup(zones, rr_name, len, labs, rr_class);
1336 	if(!z) {
1337 		z = local_zones_add_zone(zones, rr_name, len, labs, rr_class,
1338 			local_zone_transparent);
1339 		if(!z) {
1340 			lock_rw_unlock(&zones->lock);
1341 			return 0;
1342 		}
1343 	} else {
1344 		free(rr_name);
1345 	}
1346 	lock_rw_wrlock(&z->lock);
1347 	lock_rw_unlock(&zones->lock);
1348 	r = lz_enter_rr_into_zone(z, rr);
1349 	lock_rw_unlock(&z->lock);
1350 	return r;
1351 }
1352 
1353 /** returns true if the node is terminal so no deeper domain names exist */
1354 static int
1355 is_terminal(struct local_data* d)
1356 {
1357 	/* for empty nonterminals, the deeper domain names are sorted
1358 	 * right after them, so simply check the next name in the tree
1359 	 */
1360 	struct local_data* n = (struct local_data*)rbtree_next(&d->node);
1361 	if(n == (struct local_data*)RBTREE_NULL)
1362 		return 1; /* last in tree, no deeper node */
1363 	if(dname_strict_subdomain(n->name, n->namelabs, d->name, d->namelabs))
1364 		return 0; /* there is a deeper node */
1365 	return 1;
1366 }
1367 
1368 /** delete empty terminals from tree when final data is deleted */
1369 static void
1370 del_empty_term(struct local_zone* z, struct local_data* d,
1371 	uint8_t* name, size_t len, int labs)
1372 {
1373 	while(d && d->rrsets == NULL && is_terminal(d)) {
1374 		/* is this empty nonterminal? delete */
1375 		/* note, no memory recycling in zone region */
1376 		(void)rbtree_delete(&z->data, d);
1377 
1378 		/* go up and to the next label */
1379 		if(dname_is_root(name))
1380 			return;
1381 		dname_remove_label(&name, &len);
1382 		labs--;
1383 		d = lz_find_node(z, name, len, labs);
1384 	}
1385 }
1386 
1387 void local_zones_del_data(struct local_zones* zones,
1388 	uint8_t* name, size_t len, int labs, uint16_t dclass)
1389 {
1390 	/* find zone */
1391 	struct local_zone* z;
1392 	struct local_data* d;
1393 	lock_rw_rdlock(&zones->lock);
1394 	z = local_zones_lookup(zones, name, len, labs, dclass);
1395 	if(!z) {
1396 		/* no such zone, we're done */
1397 		lock_rw_unlock(&zones->lock);
1398 		return;
1399 	}
1400 	lock_rw_wrlock(&z->lock);
1401 	lock_rw_unlock(&zones->lock);
1402 
1403 	/* find the domain */
1404 	d = lz_find_node(z, name, len, labs);
1405 	if(d) {
1406 		/* no memory recycling for zone deletions ... */
1407 		d->rrsets = NULL;
1408 		/* did we delete the soa record ? */
1409 		if(query_dname_compare(d->name, z->name) == 0)
1410 			z->soa = NULL;
1411 
1412 		/* cleanup the empty nonterminals for this name */
1413 		del_empty_term(z, d, name, len, labs);
1414 	}
1415 
1416 	lock_rw_unlock(&z->lock);
1417 }
1418