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