xref: /freebsd/contrib/unbound/services/localzone.c (revision be771a7b7f4580a30d99e41a5bb1b93a385a119d)
1b7579f77SDag-Erling Smørgrav /*
2b7579f77SDag-Erling Smørgrav  * services/localzone.c - local zones authority service.
3b7579f77SDag-Erling Smørgrav  *
4b7579f77SDag-Erling Smørgrav  * Copyright (c) 2007, NLnet Labs. All rights reserved.
5b7579f77SDag-Erling Smørgrav  *
6b7579f77SDag-Erling Smørgrav  * This software is open source.
7b7579f77SDag-Erling Smørgrav  *
8b7579f77SDag-Erling Smørgrav  * Redistribution and use in source and binary forms, with or without
9b7579f77SDag-Erling Smørgrav  * modification, are permitted provided that the following conditions
10b7579f77SDag-Erling Smørgrav  * are met:
11b7579f77SDag-Erling Smørgrav  *
12b7579f77SDag-Erling Smørgrav  * Redistributions of source code must retain the above copyright notice,
13b7579f77SDag-Erling Smørgrav  * this list of conditions and the following disclaimer.
14b7579f77SDag-Erling Smørgrav  *
15b7579f77SDag-Erling Smørgrav  * Redistributions in binary form must reproduce the above copyright notice,
16b7579f77SDag-Erling Smørgrav  * this list of conditions and the following disclaimer in the documentation
17b7579f77SDag-Erling Smørgrav  * and/or other materials provided with the distribution.
18b7579f77SDag-Erling Smørgrav  *
19b7579f77SDag-Erling Smørgrav  * Neither the name of the NLNET LABS nor the names of its contributors may
20b7579f77SDag-Erling Smørgrav  * be used to endorse or promote products derived from this software without
21b7579f77SDag-Erling Smørgrav  * specific prior written permission.
22b7579f77SDag-Erling Smørgrav  *
23b7579f77SDag-Erling Smørgrav  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2417d15b25SDag-Erling Smørgrav  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2517d15b25SDag-Erling Smørgrav  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
2617d15b25SDag-Erling Smørgrav  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2717d15b25SDag-Erling Smørgrav  * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2817d15b25SDag-Erling Smørgrav  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
2917d15b25SDag-Erling Smørgrav  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
3017d15b25SDag-Erling Smørgrav  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
3117d15b25SDag-Erling Smørgrav  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
3217d15b25SDag-Erling Smørgrav  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
3317d15b25SDag-Erling Smørgrav  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34b7579f77SDag-Erling Smørgrav  */
35b7579f77SDag-Erling Smørgrav 
36b7579f77SDag-Erling Smørgrav /**
37b7579f77SDag-Erling Smørgrav  * \file
38b7579f77SDag-Erling Smørgrav  *
39b7579f77SDag-Erling Smørgrav  * This file contains functions to enable local zone authority service.
40b7579f77SDag-Erling Smørgrav  */
41b7579f77SDag-Erling Smørgrav #include "config.h"
42b7579f77SDag-Erling Smørgrav #include "services/localzone.h"
4309a3aaf3SDag-Erling Smørgrav #include "sldns/str2wire.h"
44b7579f77SDag-Erling Smørgrav #include "util/regional.h"
45b7579f77SDag-Erling Smørgrav #include "util/config_file.h"
46b7579f77SDag-Erling Smørgrav #include "util/data/dname.h"
47b7579f77SDag-Erling Smørgrav #include "util/data/packed_rrset.h"
48b7579f77SDag-Erling Smørgrav #include "util/data/msgencode.h"
49b7579f77SDag-Erling Smørgrav #include "util/net_help.h"
506480faa8SDag-Erling Smørgrav #include "util/netevent.h"
51b7579f77SDag-Erling Smørgrav #include "util/data/msgreply.h"
52b7579f77SDag-Erling Smørgrav #include "util/data/msgparse.h"
530de4f1bfSDag-Erling Smørgrav #include "util/as112.h"
54bc892140SDag-Erling Smørgrav 
55bc892140SDag-Erling Smørgrav /* maximum RRs in an RRset, to cap possible 'endless' list RRs.
56bc892140SDag-Erling Smørgrav  * with 16 bytes for an A record, a 64K packet has about 4000 max */
57bc892140SDag-Erling Smørgrav #define LOCALZONE_RRSET_COUNT_MAX 4096
58b7579f77SDag-Erling Smørgrav 
599cf5bc93SCy Schubert /** print all RRsets in local zone */
609cf5bc93SCy Schubert static void
619cf5bc93SCy Schubert local_zone_out(struct local_zone* z)
629cf5bc93SCy Schubert {
639cf5bc93SCy Schubert 	struct local_data* d;
649cf5bc93SCy Schubert 	struct local_rrset* p;
659cf5bc93SCy Schubert 	RBTREE_FOR(d, struct local_data*, &z->data) {
669cf5bc93SCy Schubert 		for(p = d->rrsets; p; p = p->next) {
679cf5bc93SCy Schubert 			log_nametypeclass(NO_VERBOSE, "rrset", d->name,
689cf5bc93SCy Schubert 				ntohs(p->rrset->rk.type),
699cf5bc93SCy Schubert 				ntohs(p->rrset->rk.rrset_class));
709cf5bc93SCy Schubert 		}
719cf5bc93SCy Schubert 	}
729cf5bc93SCy Schubert }
739cf5bc93SCy Schubert 
749cf5bc93SCy Schubert static void
759cf5bc93SCy Schubert local_zone_print(struct local_zone* z)
769cf5bc93SCy Schubert {
779cf5bc93SCy Schubert 	char buf[64];
789cf5bc93SCy Schubert 	lock_rw_rdlock(&z->lock);
799cf5bc93SCy Schubert 	snprintf(buf, sizeof(buf), "%s zone",
809cf5bc93SCy Schubert 		local_zone_type2str(z->type));
819cf5bc93SCy Schubert 	log_nametypeclass(NO_VERBOSE, buf, z->name, 0, z->dclass);
829cf5bc93SCy Schubert 	local_zone_out(z);
839cf5bc93SCy Schubert 	lock_rw_unlock(&z->lock);
849cf5bc93SCy Schubert }
859cf5bc93SCy Schubert 
869cf5bc93SCy Schubert void local_zones_print(struct local_zones* zones)
879cf5bc93SCy Schubert {
889cf5bc93SCy Schubert 	struct local_zone* z;
899cf5bc93SCy Schubert 	lock_rw_rdlock(&zones->lock);
909cf5bc93SCy Schubert 	log_info("number of auth zones %u", (unsigned)zones->ztree.count);
919cf5bc93SCy Schubert 	RBTREE_FOR(z, struct local_zone*, &zones->ztree) {
929cf5bc93SCy Schubert 		local_zone_print(z);
939cf5bc93SCy Schubert 	}
949cf5bc93SCy Schubert 	lock_rw_unlock(&zones->lock);
959cf5bc93SCy Schubert }
969cf5bc93SCy Schubert 
97b7579f77SDag-Erling Smørgrav struct local_zones*
98b7579f77SDag-Erling Smørgrav local_zones_create(void)
99b7579f77SDag-Erling Smørgrav {
100b7579f77SDag-Erling Smørgrav 	struct local_zones* zones = (struct local_zones*)calloc(1,
101b7579f77SDag-Erling Smørgrav 		sizeof(*zones));
102b7579f77SDag-Erling Smørgrav 	if(!zones)
103b7579f77SDag-Erling Smørgrav 		return NULL;
104b7579f77SDag-Erling Smørgrav 	rbtree_init(&zones->ztree, &local_zone_cmp);
10517d15b25SDag-Erling Smørgrav 	lock_rw_init(&zones->lock);
106b7579f77SDag-Erling Smørgrav 	lock_protect(&zones->lock, &zones->ztree, sizeof(zones->ztree));
107b7579f77SDag-Erling Smørgrav 	/* also lock protects the rbnode's in struct local_zone */
108b7579f77SDag-Erling Smørgrav 	return zones;
109b7579f77SDag-Erling Smørgrav }
110b7579f77SDag-Erling Smørgrav 
111b7579f77SDag-Erling Smørgrav /** helper traverse to delete zones */
112b7579f77SDag-Erling Smørgrav static void
1133005e0a3SDag-Erling Smørgrav lzdel(rbnode_type* n, void* ATTR_UNUSED(arg))
114b7579f77SDag-Erling Smørgrav {
115b7579f77SDag-Erling Smørgrav 	struct local_zone* z = (struct local_zone*)n->key;
116b7579f77SDag-Erling Smørgrav 	local_zone_delete(z);
117b7579f77SDag-Erling Smørgrav }
118b7579f77SDag-Erling Smørgrav 
119b7579f77SDag-Erling Smørgrav void
120b7579f77SDag-Erling Smørgrav local_zones_delete(struct local_zones* zones)
121b7579f77SDag-Erling Smørgrav {
122b7579f77SDag-Erling Smørgrav 	if(!zones)
123b7579f77SDag-Erling Smørgrav 		return;
12417d15b25SDag-Erling Smørgrav 	lock_rw_destroy(&zones->lock);
125b7579f77SDag-Erling Smørgrav 	/* walk through zones and delete them all */
126b7579f77SDag-Erling Smørgrav 	traverse_postorder(&zones->ztree, lzdel, NULL);
127b7579f77SDag-Erling Smørgrav 	free(zones);
128b7579f77SDag-Erling Smørgrav }
129b7579f77SDag-Erling Smørgrav 
130b7579f77SDag-Erling Smørgrav void
131b7579f77SDag-Erling Smørgrav local_zone_delete(struct local_zone* z)
132b7579f77SDag-Erling Smørgrav {
133b7579f77SDag-Erling Smørgrav 	if(!z)
134b7579f77SDag-Erling Smørgrav 		return;
135b7579f77SDag-Erling Smørgrav 	lock_rw_destroy(&z->lock);
136b7579f77SDag-Erling Smørgrav 	regional_destroy(z->region);
137b7579f77SDag-Erling Smørgrav 	free(z->name);
138e2d15004SDag-Erling Smørgrav 	free(z->taglist);
139b7579f77SDag-Erling Smørgrav 	free(z);
140b7579f77SDag-Erling Smørgrav }
141b7579f77SDag-Erling Smørgrav 
142b7579f77SDag-Erling Smørgrav int
143b7579f77SDag-Erling Smørgrav local_zone_cmp(const void* z1, const void* z2)
144b7579f77SDag-Erling Smørgrav {
145b7579f77SDag-Erling Smørgrav 	/* first sort on class, so that hierarchy can be maintained within
146b7579f77SDag-Erling Smørgrav 	 * a class */
147b7579f77SDag-Erling Smørgrav 	struct local_zone* a = (struct local_zone*)z1;
148b7579f77SDag-Erling Smørgrav 	struct local_zone* b = (struct local_zone*)z2;
149b7579f77SDag-Erling Smørgrav 	int m;
150b7579f77SDag-Erling Smørgrav 	if(a->dclass != b->dclass) {
151b7579f77SDag-Erling Smørgrav 		if(a->dclass < b->dclass)
152b7579f77SDag-Erling Smørgrav 			return -1;
153b7579f77SDag-Erling Smørgrav 		return 1;
154b7579f77SDag-Erling Smørgrav 	}
155b7579f77SDag-Erling Smørgrav 	return dname_lab_cmp(a->name, a->namelabs, b->name, b->namelabs, &m);
156b7579f77SDag-Erling Smørgrav }
157b7579f77SDag-Erling Smørgrav 
158b7579f77SDag-Erling Smørgrav int
159b7579f77SDag-Erling Smørgrav local_data_cmp(const void* d1, const void* d2)
160b7579f77SDag-Erling Smørgrav {
161b7579f77SDag-Erling Smørgrav 	struct local_data* a = (struct local_data*)d1;
162b7579f77SDag-Erling Smørgrav 	struct local_data* b = (struct local_data*)d2;
163b7579f77SDag-Erling Smørgrav 	int m;
164b7579f77SDag-Erling Smørgrav 	return dname_canon_lab_cmp(a->name, a->namelabs, b->name,
165b7579f77SDag-Erling Smørgrav 		b->namelabs, &m);
166b7579f77SDag-Erling Smørgrav }
167b7579f77SDag-Erling Smørgrav 
168b7579f77SDag-Erling Smørgrav /* form wireformat from text format domain name */
169b7579f77SDag-Erling Smørgrav int
170b7579f77SDag-Erling Smørgrav parse_dname(const char* str, uint8_t** res, size_t* len, int* labs)
171b7579f77SDag-Erling Smørgrav {
17217d15b25SDag-Erling Smørgrav 	*res = sldns_str2wire_dname(str, len);
173b7579f77SDag-Erling Smørgrav 	*labs = 0;
174b7579f77SDag-Erling Smørgrav 	if(!*res) {
17517d15b25SDag-Erling Smørgrav 		log_err("cannot parse name %s", str);
176b7579f77SDag-Erling Smørgrav 		return 0;
177b7579f77SDag-Erling Smørgrav 	}
178b7579f77SDag-Erling Smørgrav 	*labs = dname_count_size_labels(*res, len);
179b7579f77SDag-Erling Smørgrav 	return 1;
180b7579f77SDag-Erling Smørgrav }
181b7579f77SDag-Erling Smørgrav 
182b7579f77SDag-Erling Smørgrav /** create a new localzone */
183b7579f77SDag-Erling Smørgrav static struct local_zone*
184b7579f77SDag-Erling Smørgrav local_zone_create(uint8_t* nm, size_t len, int labs,
185b7579f77SDag-Erling Smørgrav 	enum localzone_type t, uint16_t dclass)
186b7579f77SDag-Erling Smørgrav {
187b7579f77SDag-Erling Smørgrav 	struct local_zone* z = (struct local_zone*)calloc(1, sizeof(*z));
188b7579f77SDag-Erling Smørgrav 	if(!z) {
189b7579f77SDag-Erling Smørgrav 		return NULL;
190b7579f77SDag-Erling Smørgrav 	}
191b7579f77SDag-Erling Smørgrav 	z->node.key = z;
192b7579f77SDag-Erling Smørgrav 	z->dclass = dclass;
193b7579f77SDag-Erling Smørgrav 	z->type = t;
194b7579f77SDag-Erling Smørgrav 	z->name = nm;
195b7579f77SDag-Erling Smørgrav 	z->namelen = len;
196b7579f77SDag-Erling Smørgrav 	z->namelabs = labs;
197b7579f77SDag-Erling Smørgrav 	lock_rw_init(&z->lock);
198369c6923SCy Schubert 	z->region = regional_create_nochunk(sizeof(struct regional));
199b7579f77SDag-Erling Smørgrav 	if(!z->region) {
200b7579f77SDag-Erling Smørgrav 		free(z);
201b7579f77SDag-Erling Smørgrav 		return NULL;
202b7579f77SDag-Erling Smørgrav 	}
203b7579f77SDag-Erling Smørgrav 	rbtree_init(&z->data, &local_data_cmp);
2043005e0a3SDag-Erling Smørgrav 	lock_protect(&z->lock, &z->parent, sizeof(*z)-sizeof(rbnode_type));
205b7579f77SDag-Erling Smørgrav 	/* also the zones->lock protects node, parent, name*, class */
206b7579f77SDag-Erling Smørgrav 	return z;
207b7579f77SDag-Erling Smørgrav }
208b7579f77SDag-Erling Smørgrav 
209b7579f77SDag-Erling Smørgrav /** enter a new zone with allocated dname returns with WRlock */
210b7579f77SDag-Erling Smørgrav static struct local_zone*
211b7579f77SDag-Erling Smørgrav lz_enter_zone_dname(struct local_zones* zones, uint8_t* nm, size_t len,
212b7579f77SDag-Erling Smørgrav 	int labs, enum localzone_type t, uint16_t c)
213b7579f77SDag-Erling Smørgrav {
214b7579f77SDag-Erling Smørgrav 	struct local_zone* z = local_zone_create(nm, len, labs, t, c);
215b7579f77SDag-Erling Smørgrav 	if(!z) {
216e2d15004SDag-Erling Smørgrav 		free(nm);
217b7579f77SDag-Erling Smørgrav 		log_err("out of memory");
218b7579f77SDag-Erling Smørgrav 		return NULL;
219b7579f77SDag-Erling Smørgrav 	}
220b7579f77SDag-Erling Smørgrav 
221b7579f77SDag-Erling Smørgrav 	/* add to rbtree */
22217d15b25SDag-Erling Smørgrav 	lock_rw_wrlock(&zones->lock);
223b7579f77SDag-Erling Smørgrav 	lock_rw_wrlock(&z->lock);
224b7579f77SDag-Erling Smørgrav 	if(!rbtree_insert(&zones->ztree, &z->node)) {
225bc892140SDag-Erling Smørgrav 		struct local_zone* oldz;
226*be771a7bSCy Schubert 		char str[LDNS_MAX_DOMAINLEN];
227c7f4d7adSDag-Erling Smørgrav 		dname_str(nm, str);
228c7f4d7adSDag-Erling Smørgrav 		log_warn("duplicate local-zone %s", str);
229b7579f77SDag-Erling Smørgrav 		lock_rw_unlock(&z->lock);
230bc892140SDag-Erling Smørgrav 		/* save zone name locally before deallocation,
231bc892140SDag-Erling Smørgrav 		 * otherwise, nm is gone if we zone_delete now. */
232bc892140SDag-Erling Smørgrav 		oldz = z;
233b5663de9SDag-Erling Smørgrav 		/* find the correct zone, so not an error for duplicate */
234b5663de9SDag-Erling Smørgrav 		z = local_zones_find(zones, nm, len, labs, c);
235b5663de9SDag-Erling Smørgrav 		lock_rw_wrlock(&z->lock);
23617d15b25SDag-Erling Smørgrav 		lock_rw_unlock(&zones->lock);
237bc892140SDag-Erling Smørgrav 		local_zone_delete(oldz);
238b5663de9SDag-Erling Smørgrav 		return z;
239b7579f77SDag-Erling Smørgrav 	}
24017d15b25SDag-Erling Smørgrav 	lock_rw_unlock(&zones->lock);
241b7579f77SDag-Erling Smørgrav 	return z;
242b7579f77SDag-Erling Smørgrav }
243b7579f77SDag-Erling Smørgrav 
244b7579f77SDag-Erling Smørgrav /** enter a new zone */
24556850988SCy Schubert struct local_zone*
246b7579f77SDag-Erling Smørgrav lz_enter_zone(struct local_zones* zones, const char* name, const char* type,
247b7579f77SDag-Erling Smørgrav 	uint16_t dclass)
248b7579f77SDag-Erling Smørgrav {
249b7579f77SDag-Erling Smørgrav 	struct local_zone* z;
250b7579f77SDag-Erling Smørgrav 	enum localzone_type t;
251b7579f77SDag-Erling Smørgrav 	uint8_t* nm;
252b7579f77SDag-Erling Smørgrav 	size_t len;
253b7579f77SDag-Erling Smørgrav 	int labs;
254b7579f77SDag-Erling Smørgrav 	if(!parse_dname(name, &nm, &len, &labs)) {
255b7579f77SDag-Erling Smørgrav 		log_err("bad zone name %s %s", name, type);
256b7579f77SDag-Erling Smørgrav 		return NULL;
257b7579f77SDag-Erling Smørgrav 	}
258b7579f77SDag-Erling Smørgrav 	if(!local_zone_str2type(type, &t)) {
259b7579f77SDag-Erling Smørgrav 		log_err("bad lz_enter_zone type %s %s", name, type);
260b7579f77SDag-Erling Smørgrav 		free(nm);
261b7579f77SDag-Erling Smørgrav 		return NULL;
262b7579f77SDag-Erling Smørgrav 	}
263b7579f77SDag-Erling Smørgrav 	if(!(z=lz_enter_zone_dname(zones, nm, len, labs, t, dclass))) {
264b7579f77SDag-Erling Smørgrav 		log_err("could not enter zone %s %s", name, type);
265b7579f77SDag-Erling Smørgrav 		return NULL;
266b7579f77SDag-Erling Smørgrav 	}
267b7579f77SDag-Erling Smørgrav 	return z;
268b7579f77SDag-Erling Smørgrav }
269b7579f77SDag-Erling Smørgrav 
27065b390aaSDag-Erling Smørgrav int
27165b390aaSDag-Erling Smørgrav rrstr_get_rr_content(const char* str, uint8_t** nm, uint16_t* type,
27217d15b25SDag-Erling Smørgrav 	uint16_t* dclass, time_t* ttl, uint8_t* rr, size_t len,
27317d15b25SDag-Erling Smørgrav 	uint8_t** rdata, size_t* rdata_len)
274b7579f77SDag-Erling Smørgrav {
27517d15b25SDag-Erling Smørgrav 	size_t dname_len = 0;
27617d15b25SDag-Erling Smørgrav 	int e = sldns_str2wire_rr_buf(str, rr, &len, &dname_len, 3600,
27717d15b25SDag-Erling Smørgrav 		NULL, 0, NULL, 0);
27817d15b25SDag-Erling Smørgrav 	if(e) {
27917d15b25SDag-Erling Smørgrav 		log_err("error parsing local-data at %d: '%s': %s",
28017d15b25SDag-Erling Smørgrav 			LDNS_WIREPARSE_OFFSET(e), str,
28117d15b25SDag-Erling Smørgrav 			sldns_get_errorstr_parse(e));
282b7579f77SDag-Erling Smørgrav 		return 0;
283b7579f77SDag-Erling Smørgrav 	}
28417d15b25SDag-Erling Smørgrav 	*nm = memdup(rr, dname_len);
285b7579f77SDag-Erling Smørgrav 	if(!*nm) {
286b7579f77SDag-Erling Smørgrav 		log_err("out of memory");
287b7579f77SDag-Erling Smørgrav 		return 0;
288b7579f77SDag-Erling Smørgrav 	}
28917d15b25SDag-Erling Smørgrav 	*dclass = sldns_wirerr_get_class(rr, len, dname_len);
29017d15b25SDag-Erling Smørgrav 	*type = sldns_wirerr_get_type(rr, len, dname_len);
29117d15b25SDag-Erling Smørgrav 	*ttl = (time_t)sldns_wirerr_get_ttl(rr, len, dname_len);
29217d15b25SDag-Erling Smørgrav 	*rdata = sldns_wirerr_get_rdatawl(rr, len, dname_len);
29317d15b25SDag-Erling Smørgrav 	*rdata_len = sldns_wirerr_get_rdatalen(rr, len, dname_len)+2;
294b7579f77SDag-Erling Smørgrav 	return 1;
295b7579f77SDag-Erling Smørgrav }
296b7579f77SDag-Erling Smørgrav 
297b7579f77SDag-Erling Smørgrav /** return name and class of rr; parses string */
298b7579f77SDag-Erling Smørgrav static int
299971980c3SDag-Erling Smørgrav get_rr_nameclass(const char* str, uint8_t** nm, uint16_t* dclass,
300971980c3SDag-Erling Smørgrav 	uint16_t* dtype)
301b7579f77SDag-Erling Smørgrav {
30217d15b25SDag-Erling Smørgrav 	uint8_t rr[LDNS_RR_BUF_SIZE];
30317d15b25SDag-Erling Smørgrav 	size_t len = sizeof(rr), dname_len = 0;
30417d15b25SDag-Erling Smørgrav 	int s = sldns_str2wire_rr_buf(str, rr, &len, &dname_len, 3600,
30517d15b25SDag-Erling Smørgrav 		NULL, 0, NULL, 0);
30617d15b25SDag-Erling Smørgrav 	if(s != 0) {
30717d15b25SDag-Erling Smørgrav 		log_err("error parsing local-data at %d '%s': %s",
30817d15b25SDag-Erling Smørgrav 			LDNS_WIREPARSE_OFFSET(s), str,
30917d15b25SDag-Erling Smørgrav 			sldns_get_errorstr_parse(s));
310b7579f77SDag-Erling Smørgrav 		return 0;
311b7579f77SDag-Erling Smørgrav 	}
31217d15b25SDag-Erling Smørgrav 	*nm = memdup(rr, dname_len);
31317d15b25SDag-Erling Smørgrav 	*dclass = sldns_wirerr_get_class(rr, len, dname_len);
314971980c3SDag-Erling Smørgrav 	*dtype = sldns_wirerr_get_type(rr, len, dname_len);
315b7579f77SDag-Erling Smørgrav 	if(!*nm) {
316b7579f77SDag-Erling Smørgrav 		log_err("out of memory");
317b7579f77SDag-Erling Smørgrav 		return 0;
318b7579f77SDag-Erling Smørgrav 	}
319b7579f77SDag-Erling Smørgrav 	return 1;
320b7579f77SDag-Erling Smørgrav }
321b7579f77SDag-Erling Smørgrav 
322b7579f77SDag-Erling Smørgrav /**
323b7579f77SDag-Erling Smørgrav  * Find an rrset in local data structure.
324b7579f77SDag-Erling Smørgrav  * @param data: local data domain name structure.
325b7579f77SDag-Erling Smørgrav  * @param type: type to look for (host order).
326bc892140SDag-Erling Smørgrav  * @param alias_ok: 1 if matching a non-exact, alias type such as CNAME is
327bc892140SDag-Erling Smørgrav  * allowed.  otherwise 0.
328b7579f77SDag-Erling Smørgrav  * @return rrset pointer or NULL if not found.
329b7579f77SDag-Erling Smørgrav  */
330b7579f77SDag-Erling Smørgrav static struct local_rrset*
331bc892140SDag-Erling Smørgrav local_data_find_type(struct local_data* data, uint16_t type, int alias_ok)
332b7579f77SDag-Erling Smørgrav {
333335c7cdaSCy Schubert 	struct local_rrset* p, *cname = NULL;
334b7579f77SDag-Erling Smørgrav 	type = htons(type);
335b7579f77SDag-Erling Smørgrav 	for(p = data->rrsets; p; p = p->next) {
336b7579f77SDag-Erling Smørgrav 		if(p->rrset->rk.type == type)
337b7579f77SDag-Erling Smørgrav 			return p;
338bc892140SDag-Erling Smørgrav 		if(alias_ok && p->rrset->rk.type == htons(LDNS_RR_TYPE_CNAME))
339335c7cdaSCy Schubert 			cname = p;
340b7579f77SDag-Erling Smørgrav 	}
341335c7cdaSCy Schubert 	if(alias_ok)
342335c7cdaSCy Schubert 		return cname;
343b7579f77SDag-Erling Smørgrav 	return NULL;
344b7579f77SDag-Erling Smørgrav }
345b7579f77SDag-Erling Smørgrav 
346b7579f77SDag-Erling Smørgrav /** check for RR duplicates */
347b7579f77SDag-Erling Smørgrav static int
34817d15b25SDag-Erling Smørgrav rr_is_duplicate(struct packed_rrset_data* pd, uint8_t* rdata, size_t rdata_len)
349b7579f77SDag-Erling Smørgrav {
350b7579f77SDag-Erling Smørgrav 	size_t i;
351b7579f77SDag-Erling Smørgrav 	for(i=0; i<pd->count; i++) {
35217d15b25SDag-Erling Smørgrav 		if(pd->rr_len[i] == rdata_len &&
35317d15b25SDag-Erling Smørgrav 			memcmp(pd->rr_data[i], rdata, rdata_len) == 0)
354b7579f77SDag-Erling Smørgrav 			return 1;
355b7579f77SDag-Erling Smørgrav 	}
356b7579f77SDag-Erling Smørgrav 	return 0;
357b7579f77SDag-Erling Smørgrav }
358b7579f77SDag-Erling Smørgrav 
359b7579f77SDag-Erling Smørgrav /** new local_rrset */
360b7579f77SDag-Erling Smørgrav static struct local_rrset*
361b7579f77SDag-Erling Smørgrav new_local_rrset(struct regional* region, struct local_data* node,
362b7579f77SDag-Erling Smørgrav 	uint16_t rrtype, uint16_t rrclass)
363b7579f77SDag-Erling Smørgrav {
364b7579f77SDag-Erling Smørgrav 	struct packed_rrset_data* pd;
365b7579f77SDag-Erling Smørgrav 	struct local_rrset* rrset = (struct local_rrset*)
366b7579f77SDag-Erling Smørgrav 		regional_alloc_zero(region, sizeof(*rrset));
367b7579f77SDag-Erling Smørgrav 	if(!rrset) {
368b7579f77SDag-Erling Smørgrav 		log_err("out of memory");
369b7579f77SDag-Erling Smørgrav 		return NULL;
370b7579f77SDag-Erling Smørgrav 	}
371b7579f77SDag-Erling Smørgrav 	rrset->next = node->rrsets;
372b7579f77SDag-Erling Smørgrav 	node->rrsets = rrset;
373b7579f77SDag-Erling Smørgrav 	rrset->rrset = (struct ub_packed_rrset_key*)
374b7579f77SDag-Erling Smørgrav 		regional_alloc_zero(region, sizeof(*rrset->rrset));
375b7579f77SDag-Erling Smørgrav 	if(!rrset->rrset) {
376b7579f77SDag-Erling Smørgrav 		log_err("out of memory");
377b7579f77SDag-Erling Smørgrav 		return NULL;
378b7579f77SDag-Erling Smørgrav 	}
379b7579f77SDag-Erling Smørgrav 	rrset->rrset->entry.key = rrset->rrset;
380b7579f77SDag-Erling Smørgrav 	pd = (struct packed_rrset_data*)regional_alloc_zero(region,
381b7579f77SDag-Erling Smørgrav 		sizeof(*pd));
382b7579f77SDag-Erling Smørgrav 	if(!pd) {
383b7579f77SDag-Erling Smørgrav 		log_err("out of memory");
384b7579f77SDag-Erling Smørgrav 		return NULL;
385b7579f77SDag-Erling Smørgrav 	}
386b7579f77SDag-Erling Smørgrav 	pd->trust = rrset_trust_prim_noglue;
387b7579f77SDag-Erling Smørgrav 	pd->security = sec_status_insecure;
388b7579f77SDag-Erling Smørgrav 	rrset->rrset->entry.data = pd;
389b7579f77SDag-Erling Smørgrav 	rrset->rrset->rk.dname = node->name;
390b7579f77SDag-Erling Smørgrav 	rrset->rrset->rk.dname_len = node->namelen;
391b7579f77SDag-Erling Smørgrav 	rrset->rrset->rk.type = htons(rrtype);
392b7579f77SDag-Erling Smørgrav 	rrset->rrset->rk.rrset_class = htons(rrclass);
393b7579f77SDag-Erling Smørgrav 	return rrset;
394b7579f77SDag-Erling Smørgrav }
395b7579f77SDag-Erling Smørgrav 
396b7579f77SDag-Erling Smørgrav /** insert RR into RRset data structure; Wastes a couple of bytes */
39765b390aaSDag-Erling Smørgrav int
39865b390aaSDag-Erling Smørgrav rrset_insert_rr(struct regional* region, struct packed_rrset_data* pd,
399bc892140SDag-Erling Smørgrav 	uint8_t* rdata, size_t rdata_len, time_t ttl, const char* rrstr)
400b7579f77SDag-Erling Smørgrav {
401b7579f77SDag-Erling Smørgrav 	size_t* oldlen = pd->rr_len;
40217d15b25SDag-Erling Smørgrav 	time_t* oldttl = pd->rr_ttl;
403b7579f77SDag-Erling Smørgrav 	uint8_t** olddata = pd->rr_data;
404b7579f77SDag-Erling Smørgrav 
405b7579f77SDag-Erling Smørgrav 	/* add RR to rrset */
406bc892140SDag-Erling Smørgrav 	if(pd->count > LOCALZONE_RRSET_COUNT_MAX) {
407bc892140SDag-Erling Smørgrav 		log_warn("RRset '%s' has more than %d records, record ignored",
408bc892140SDag-Erling Smørgrav 			rrstr, LOCALZONE_RRSET_COUNT_MAX);
409bc892140SDag-Erling Smørgrav 		return 1;
410bc892140SDag-Erling Smørgrav 	}
411b7579f77SDag-Erling Smørgrav 	pd->count++;
412b7579f77SDag-Erling Smørgrav 	pd->rr_len = regional_alloc(region, sizeof(*pd->rr_len)*pd->count);
413b7579f77SDag-Erling Smørgrav 	pd->rr_ttl = regional_alloc(region, sizeof(*pd->rr_ttl)*pd->count);
414b7579f77SDag-Erling Smørgrav 	pd->rr_data = regional_alloc(region, sizeof(*pd->rr_data)*pd->count);
415b7579f77SDag-Erling Smørgrav 	if(!pd->rr_len || !pd->rr_ttl || !pd->rr_data) {
416b7579f77SDag-Erling Smørgrav 		log_err("out of memory");
417b7579f77SDag-Erling Smørgrav 		return 0;
418b7579f77SDag-Erling Smørgrav 	}
419b7579f77SDag-Erling Smørgrav 	if(pd->count > 1) {
420b7579f77SDag-Erling Smørgrav 		memcpy(pd->rr_len+1, oldlen,
421b7579f77SDag-Erling Smørgrav 			sizeof(*pd->rr_len)*(pd->count-1));
422b7579f77SDag-Erling Smørgrav 		memcpy(pd->rr_ttl+1, oldttl,
423b7579f77SDag-Erling Smørgrav 			sizeof(*pd->rr_ttl)*(pd->count-1));
424b7579f77SDag-Erling Smørgrav 		memcpy(pd->rr_data+1, olddata,
425b7579f77SDag-Erling Smørgrav 			sizeof(*pd->rr_data)*(pd->count-1));
426b7579f77SDag-Erling Smørgrav 	}
42717d15b25SDag-Erling Smørgrav 	pd->rr_len[0] = rdata_len;
428b7579f77SDag-Erling Smørgrav 	pd->rr_ttl[0] = ttl;
42917d15b25SDag-Erling Smørgrav 	pd->rr_data[0] = regional_alloc_init(region, rdata, rdata_len);
430b7579f77SDag-Erling Smørgrav 	if(!pd->rr_data[0]) {
431b7579f77SDag-Erling Smørgrav 		log_err("out of memory");
432b7579f77SDag-Erling Smørgrav 		return 0;
433b7579f77SDag-Erling Smørgrav 	}
434b7579f77SDag-Erling Smørgrav 	return 1;
435b7579f77SDag-Erling Smørgrav }
436b7579f77SDag-Erling Smørgrav 
437091e9e46SCy Schubert /** Delete RR from local-zone RRset, wastes memory as the deleted RRs cannot be
438091e9e46SCy Schubert  * free'd (regionally alloc'd) */
439091e9e46SCy Schubert int
440091e9e46SCy Schubert local_rrset_remove_rr(struct packed_rrset_data* pd, size_t index)
441091e9e46SCy Schubert {
442091e9e46SCy Schubert 	log_assert(pd->count > 0);
443091e9e46SCy Schubert 	if(index >= pd->count) {
444091e9e46SCy Schubert 		log_warn("Trying to remove RR with out of bound index");
445091e9e46SCy Schubert 		return 0;
446091e9e46SCy Schubert 	}
447091e9e46SCy Schubert 	if(index + 1 < pd->count) {
448091e9e46SCy Schubert 		/* not removing last element */
449091e9e46SCy Schubert 		size_t nexti = index + 1;
450091e9e46SCy Schubert 		size_t num = pd->count - nexti;
451091e9e46SCy Schubert 		memmove(pd->rr_len+index, pd->rr_len+nexti, sizeof(*pd->rr_len)*num);
452091e9e46SCy Schubert 		memmove(pd->rr_ttl+index, pd->rr_ttl+nexti, sizeof(*pd->rr_ttl)*num);
453091e9e46SCy Schubert 		memmove(pd->rr_data+index, pd->rr_data+nexti, sizeof(*pd->rr_data)*num);
454091e9e46SCy Schubert 	}
455091e9e46SCy Schubert 	pd->count--;
456091e9e46SCy Schubert 	return 1;
457091e9e46SCy Schubert }
458091e9e46SCy Schubert 
459091e9e46SCy Schubert struct local_data*
460091e9e46SCy Schubert local_zone_find_data(struct local_zone* z, uint8_t* nm, size_t nmlen, int nmlabs)
461b7579f77SDag-Erling Smørgrav {
462b7579f77SDag-Erling Smørgrav 	struct local_data key;
463b7579f77SDag-Erling Smørgrav 	key.node.key = &key;
464b7579f77SDag-Erling Smørgrav 	key.name = nm;
465b7579f77SDag-Erling Smørgrav 	key.namelen = nmlen;
466b7579f77SDag-Erling Smørgrav 	key.namelabs = nmlabs;
467b7579f77SDag-Erling Smørgrav 	return (struct local_data*)rbtree_search(&z->data, &key.node);
468b7579f77SDag-Erling Smørgrav }
469b7579f77SDag-Erling Smørgrav 
470b7579f77SDag-Erling Smørgrav /** find a node, create it if not and all its empty nonterminal parents */
471b7579f77SDag-Erling Smørgrav static int
472b7579f77SDag-Erling Smørgrav lz_find_create_node(struct local_zone* z, uint8_t* nm, size_t nmlen,
473b7579f77SDag-Erling Smørgrav 	int nmlabs, struct local_data** res)
474b7579f77SDag-Erling Smørgrav {
475091e9e46SCy Schubert 	struct local_data* ld = local_zone_find_data(z, nm, nmlen, nmlabs);
476b7579f77SDag-Erling Smørgrav 	if(!ld) {
477b7579f77SDag-Erling Smørgrav 		/* create a domain name to store rr. */
478b7579f77SDag-Erling Smørgrav 		ld = (struct local_data*)regional_alloc_zero(z->region,
479b7579f77SDag-Erling Smørgrav 			sizeof(*ld));
480b7579f77SDag-Erling Smørgrav 		if(!ld) {
481b7579f77SDag-Erling Smørgrav 			log_err("out of memory adding local data");
482b7579f77SDag-Erling Smørgrav 			return 0;
483b7579f77SDag-Erling Smørgrav 		}
484b7579f77SDag-Erling Smørgrav 		ld->node.key = ld;
485b7579f77SDag-Erling Smørgrav 		ld->name = regional_alloc_init(z->region, nm, nmlen);
486b7579f77SDag-Erling Smørgrav 		if(!ld->name) {
487b7579f77SDag-Erling Smørgrav 			log_err("out of memory");
488b7579f77SDag-Erling Smørgrav 			return 0;
489b7579f77SDag-Erling Smørgrav 		}
490b7579f77SDag-Erling Smørgrav 		ld->namelen = nmlen;
491b7579f77SDag-Erling Smørgrav 		ld->namelabs = nmlabs;
492b7579f77SDag-Erling Smørgrav 		if(!rbtree_insert(&z->data, &ld->node)) {
493b7579f77SDag-Erling Smørgrav 			log_assert(0); /* duplicate name */
494b7579f77SDag-Erling Smørgrav 		}
495b7579f77SDag-Erling Smørgrav 		/* see if empty nonterminals need to be created */
496b7579f77SDag-Erling Smørgrav 		if(nmlabs > z->namelabs) {
497b7579f77SDag-Erling Smørgrav 			dname_remove_label(&nm, &nmlen);
498b7579f77SDag-Erling Smørgrav 			if(!lz_find_create_node(z, nm, nmlen, nmlabs-1, res))
499b7579f77SDag-Erling Smørgrav 				return 0;
500b7579f77SDag-Erling Smørgrav 		}
501b7579f77SDag-Erling Smørgrav 	}
502b7579f77SDag-Erling Smørgrav 	*res = ld;
503b7579f77SDag-Erling Smørgrav 	return 1;
504b7579f77SDag-Erling Smørgrav }
505b7579f77SDag-Erling Smørgrav 
506f44e67d1SCy Schubert /* Mark the SOA record for the zone. This only marks the SOA rrset; the data
507f44e67d1SCy Schubert  * for the RR is entered later on local_zone_enter_rr() as with the other
50824e36522SCy Schubert  * records. An artificial soa_negative record with a modified TTL (minimum of
509f44e67d1SCy Schubert  * the TTL and the SOA.MINIMUM) is also created and marked for usage with
510f44e67d1SCy Schubert  * negative answers and to avoid allocations during those answers. */
511f44e67d1SCy Schubert static int
512f44e67d1SCy Schubert lz_mark_soa_for_zone(struct local_zone* z, struct ub_packed_rrset_key* soa_rrset,
513f44e67d1SCy Schubert 	uint8_t* rdata, size_t rdata_len, time_t ttl, const char* rrstr)
514f44e67d1SCy Schubert {
515f44e67d1SCy Schubert 	struct packed_rrset_data* pd = (struct packed_rrset_data*)
516f44e67d1SCy Schubert 		regional_alloc_zero(z->region, sizeof(*pd));
517f44e67d1SCy Schubert 	struct ub_packed_rrset_key* rrset_negative = (struct ub_packed_rrset_key*)
518f44e67d1SCy Schubert 		regional_alloc_zero(z->region, sizeof(*rrset_negative));
519f44e67d1SCy Schubert 	time_t minimum;
520f44e67d1SCy Schubert 	if(!rrset_negative||!pd) {
521f44e67d1SCy Schubert 		log_err("out of memory");
522f44e67d1SCy Schubert 		return 0;
523f44e67d1SCy Schubert 	}
524f44e67d1SCy Schubert 	/* Mark the original SOA record and then continue with the negative one. */
525f44e67d1SCy Schubert 	z->soa = soa_rrset;
526f44e67d1SCy Schubert 	rrset_negative->entry.key = rrset_negative;
527f44e67d1SCy Schubert 	pd->trust = rrset_trust_prim_noglue;
528f44e67d1SCy Schubert 	pd->security = sec_status_insecure;
529f44e67d1SCy Schubert 	rrset_negative->entry.data = pd;
530f44e67d1SCy Schubert 	rrset_negative->rk.dname = soa_rrset->rk.dname;
531f44e67d1SCy Schubert 	rrset_negative->rk.dname_len = soa_rrset->rk.dname_len;
532f44e67d1SCy Schubert 	rrset_negative->rk.type = soa_rrset->rk.type;
533f44e67d1SCy Schubert 	rrset_negative->rk.rrset_class = soa_rrset->rk.rrset_class;
534f44e67d1SCy Schubert 	if(!rrset_insert_rr(z->region, pd, rdata, rdata_len, ttl, rrstr))
535f44e67d1SCy Schubert 		return 0;
536f44e67d1SCy Schubert 	/* last 4 bytes are minimum ttl in network format */
537f44e67d1SCy Schubert 	if(pd->count == 0 || pd->rr_len[0] < 2+4)
538f44e67d1SCy Schubert 		return 0;
539f44e67d1SCy Schubert 	minimum = (time_t)sldns_read_uint32(pd->rr_data[0]+(pd->rr_len[0]-4));
540f44e67d1SCy Schubert 	minimum = ttl<minimum?ttl:minimum;
541f44e67d1SCy Schubert 	pd->ttl = minimum;
542f44e67d1SCy Schubert 	pd->rr_ttl[0] = minimum;
543f44e67d1SCy Schubert 
544f44e67d1SCy Schubert 	z->soa_negative = rrset_negative;
545f44e67d1SCy Schubert 	return 1;
546f44e67d1SCy Schubert }
547f44e67d1SCy Schubert 
548091e9e46SCy Schubert int
549091e9e46SCy Schubert local_zone_enter_rr(struct local_zone* z, uint8_t* nm, size_t nmlen,
550091e9e46SCy Schubert 	int nmlabs, uint16_t rrtype, uint16_t rrclass, time_t ttl,
551091e9e46SCy Schubert 	uint8_t* rdata, size_t rdata_len, const char* rrstr)
552b7579f77SDag-Erling Smørgrav {
553b7579f77SDag-Erling Smørgrav 	struct local_data* node;
554b7579f77SDag-Erling Smørgrav 	struct local_rrset* rrset;
555b7579f77SDag-Erling Smørgrav 	struct packed_rrset_data* pd;
556091e9e46SCy Schubert 
557b7579f77SDag-Erling Smørgrav 	if(!lz_find_create_node(z, nm, nmlen, nmlabs, &node)) {
558b7579f77SDag-Erling Smørgrav 		return 0;
559b7579f77SDag-Erling Smørgrav 	}
560b7579f77SDag-Erling Smørgrav 	log_assert(node);
561b7579f77SDag-Erling Smørgrav 
562bc892140SDag-Erling Smørgrav 	/* Reject it if we would end up having CNAME and other data (including
563bc892140SDag-Erling Smørgrav 	 * another CNAME) for a redirect zone. */
564e86b9096SDag-Erling Smørgrav 	if((z->type == local_zone_redirect ||
565e86b9096SDag-Erling Smørgrav 		z->type == local_zone_inform_redirect) && node->rrsets) {
566bc892140SDag-Erling Smørgrav 		const char* othertype = NULL;
567bc892140SDag-Erling Smørgrav 		if (rrtype == LDNS_RR_TYPE_CNAME)
568bc892140SDag-Erling Smørgrav 			othertype = "other";
569bc892140SDag-Erling Smørgrav 		else if (node->rrsets->rrset->rk.type ==
570bc892140SDag-Erling Smørgrav 			 htons(LDNS_RR_TYPE_CNAME)) {
571bc892140SDag-Erling Smørgrav 			othertype = "CNAME";
572bc892140SDag-Erling Smørgrav 		}
573bc892140SDag-Erling Smørgrav 		if(othertype) {
574bc892140SDag-Erling Smørgrav 			log_err("local-data '%s' in redirect zone must not "
575bc892140SDag-Erling Smørgrav 				"coexist with %s local-data", rrstr, othertype);
576bc892140SDag-Erling Smørgrav 			return 0;
577bc892140SDag-Erling Smørgrav 		}
578bc892140SDag-Erling Smørgrav 	}
579bc892140SDag-Erling Smørgrav 	rrset = local_data_find_type(node, rrtype, 0);
580b7579f77SDag-Erling Smørgrav 	if(!rrset) {
581b7579f77SDag-Erling Smørgrav 		rrset = new_local_rrset(z->region, node, rrtype, rrclass);
582b7579f77SDag-Erling Smørgrav 		if(!rrset)
583b7579f77SDag-Erling Smørgrav 			return 0;
584b7579f77SDag-Erling Smørgrav 		if(query_dname_compare(node->name, z->name) == 0) {
585b7579f77SDag-Erling Smørgrav 			if(rrtype == LDNS_RR_TYPE_NSEC)
586b7579f77SDag-Erling Smørgrav 			  rrset->rrset->rk.flags = PACKED_RRSET_NSEC_AT_APEX;
587f44e67d1SCy Schubert 			if(rrtype == LDNS_RR_TYPE_SOA &&
588f44e67d1SCy Schubert 				!lz_mark_soa_for_zone(z, rrset->rrset, rdata, rdata_len, ttl,
589f44e67d1SCy Schubert 					rrstr))
590f44e67d1SCy Schubert 				return 0;
591b7579f77SDag-Erling Smørgrav 		}
592b7579f77SDag-Erling Smørgrav 	}
593b7579f77SDag-Erling Smørgrav 	pd = (struct packed_rrset_data*)rrset->rrset->entry.data;
594b7579f77SDag-Erling Smørgrav 	log_assert(rrset && pd);
595b7579f77SDag-Erling Smørgrav 
596b7579f77SDag-Erling Smørgrav 	/* check for duplicate RR */
59717d15b25SDag-Erling Smørgrav 	if(rr_is_duplicate(pd, rdata, rdata_len)) {
598b7579f77SDag-Erling Smørgrav 		verbose(VERB_ALGO, "ignoring duplicate RR: %s", rrstr);
599b7579f77SDag-Erling Smørgrav 		return 1;
600b7579f77SDag-Erling Smørgrav 	}
60165b390aaSDag-Erling Smørgrav 	return rrset_insert_rr(z->region, pd, rdata, rdata_len, ttl, rrstr);
602b7579f77SDag-Erling Smørgrav }
603b7579f77SDag-Erling Smørgrav 
604091e9e46SCy Schubert /** enter data RR into auth zone */
60525039b37SCy Schubert static int
606091e9e46SCy Schubert lz_enter_rr_into_zone(struct local_zone* z, const char* rrstr)
607091e9e46SCy Schubert {
608091e9e46SCy Schubert 	uint8_t* nm;
609091e9e46SCy Schubert 	size_t nmlen;
610091e9e46SCy Schubert 	int nmlabs, ret;
611091e9e46SCy Schubert 	uint16_t rrtype = 0, rrclass = 0;
612091e9e46SCy Schubert 	time_t ttl = 0;
613091e9e46SCy Schubert 	uint8_t rr[LDNS_RR_BUF_SIZE];
614091e9e46SCy Schubert 	uint8_t* rdata;
615091e9e46SCy Schubert 	size_t rdata_len;
616091e9e46SCy Schubert 	if(!rrstr_get_rr_content(rrstr, &nm, &rrtype, &rrclass, &ttl, rr,
617091e9e46SCy Schubert 		sizeof(rr), &rdata, &rdata_len)) {
618091e9e46SCy Schubert 		log_err("bad local-data: %s", rrstr);
619091e9e46SCy Schubert 		return 0;
620091e9e46SCy Schubert 	}
621091e9e46SCy Schubert 	log_assert(z->dclass == rrclass);
622091e9e46SCy Schubert 	if((z->type == local_zone_redirect ||
623091e9e46SCy Schubert 		z->type == local_zone_inform_redirect) &&
624091e9e46SCy Schubert 		query_dname_compare(z->name, nm) != 0) {
625091e9e46SCy Schubert 		log_err("local-data in redirect zone must reside at top of zone"
626091e9e46SCy Schubert 			", not at %s", rrstr);
627091e9e46SCy Schubert 		free(nm);
628091e9e46SCy Schubert 		return 0;
629091e9e46SCy Schubert 	}
630091e9e46SCy Schubert 	nmlabs = dname_count_size_labels(nm, &nmlen);
631091e9e46SCy Schubert 	ret = local_zone_enter_rr(z, nm, nmlen, nmlabs, rrtype, rrclass, ttl,
632091e9e46SCy Schubert 		rdata, rdata_len, rrstr);
633091e9e46SCy Schubert 	free(nm);
634091e9e46SCy Schubert 	return ret;
635091e9e46SCy Schubert }
636091e9e46SCy Schubert 
637b7579f77SDag-Erling Smørgrav /** enter a data RR into auth data; a zone for it must exist */
638b7579f77SDag-Erling Smørgrav static int
63917d15b25SDag-Erling Smørgrav lz_enter_rr_str(struct local_zones* zones, const char* rr)
640b7579f77SDag-Erling Smørgrav {
641b7579f77SDag-Erling Smørgrav 	uint8_t* rr_name;
642971980c3SDag-Erling Smørgrav 	uint16_t rr_class, rr_type;
643b7579f77SDag-Erling Smørgrav 	size_t len;
644b7579f77SDag-Erling Smørgrav 	int labs;
645b7579f77SDag-Erling Smørgrav 	struct local_zone* z;
646b7579f77SDag-Erling Smørgrav 	int r;
647971980c3SDag-Erling Smørgrav 	if(!get_rr_nameclass(rr, &rr_name, &rr_class, &rr_type)) {
648b7579f77SDag-Erling Smørgrav 		log_err("bad rr %s", rr);
649b7579f77SDag-Erling Smørgrav 		return 0;
650b7579f77SDag-Erling Smørgrav 	}
651b7579f77SDag-Erling Smørgrav 	labs = dname_count_size_labels(rr_name, &len);
65217d15b25SDag-Erling Smørgrav 	lock_rw_rdlock(&zones->lock);
653971980c3SDag-Erling Smørgrav 	z = local_zones_lookup(zones, rr_name, len, labs, rr_class, rr_type);
654b7579f77SDag-Erling Smørgrav 	if(!z) {
65517d15b25SDag-Erling Smørgrav 		lock_rw_unlock(&zones->lock);
656b7579f77SDag-Erling Smørgrav 		fatal_exit("internal error: no zone for rr %s", rr);
657b7579f77SDag-Erling Smørgrav 	}
658b7579f77SDag-Erling Smørgrav 	lock_rw_wrlock(&z->lock);
65917d15b25SDag-Erling Smørgrav 	lock_rw_unlock(&zones->lock);
660b7579f77SDag-Erling Smørgrav 	free(rr_name);
66117d15b25SDag-Erling Smørgrav 	r = lz_enter_rr_into_zone(z, rr);
662b7579f77SDag-Erling Smørgrav 	lock_rw_unlock(&z->lock);
663b7579f77SDag-Erling Smørgrav 	return r;
664b7579f77SDag-Erling Smørgrav }
665b7579f77SDag-Erling Smørgrav 
666e2d15004SDag-Erling Smørgrav /** enter tagstring into zone */
667e2d15004SDag-Erling Smørgrav static int
668e2d15004SDag-Erling Smørgrav lz_enter_zone_tag(struct local_zones* zones, char* zname, uint8_t* list,
669e2d15004SDag-Erling Smørgrav 	size_t len, uint16_t rr_class)
670e2d15004SDag-Erling Smørgrav {
671e2d15004SDag-Erling Smørgrav 	uint8_t dname[LDNS_MAX_DOMAINLEN+1];
672e2d15004SDag-Erling Smørgrav 	size_t dname_len = sizeof(dname);
673e2d15004SDag-Erling Smørgrav 	int dname_labs, r = 0;
674e2d15004SDag-Erling Smørgrav 	struct local_zone* z;
675e2d15004SDag-Erling Smørgrav 
676e2d15004SDag-Erling Smørgrav 	if(sldns_str2wire_dname_buf(zname, dname, &dname_len) != 0) {
677e2d15004SDag-Erling Smørgrav 		log_err("cannot parse zone name in local-zone-tag: %s", zname);
678e2d15004SDag-Erling Smørgrav 		return 0;
679e2d15004SDag-Erling Smørgrav 	}
680e2d15004SDag-Erling Smørgrav 	dname_labs = dname_count_labels(dname);
681e2d15004SDag-Erling Smørgrav 
682e2d15004SDag-Erling Smørgrav 	lock_rw_rdlock(&zones->lock);
683b5663de9SDag-Erling Smørgrav 	z = local_zones_find(zones, dname, dname_len, dname_labs, rr_class);
684e2d15004SDag-Erling Smørgrav 	if(!z) {
685e2d15004SDag-Erling Smørgrav 		lock_rw_unlock(&zones->lock);
686e2d15004SDag-Erling Smørgrav 		log_err("no local-zone for tag %s", zname);
687e2d15004SDag-Erling Smørgrav 		return 0;
688e2d15004SDag-Erling Smørgrav 	}
689e2d15004SDag-Erling Smørgrav 	lock_rw_wrlock(&z->lock);
690e2d15004SDag-Erling Smørgrav 	lock_rw_unlock(&zones->lock);
691e2d15004SDag-Erling Smørgrav 	free(z->taglist);
692e2d15004SDag-Erling Smørgrav 	z->taglist = memdup(list, len);
693e2d15004SDag-Erling Smørgrav 	z->taglen = len;
694e2d15004SDag-Erling Smørgrav 	if(z->taglist)
695e2d15004SDag-Erling Smørgrav 		r = 1;
696e2d15004SDag-Erling Smørgrav 	lock_rw_unlock(&z->lock);
697e2d15004SDag-Erling Smørgrav 	return r;
698e2d15004SDag-Erling Smørgrav }
699e2d15004SDag-Erling Smørgrav 
700b5663de9SDag-Erling Smørgrav /** enter override into zone */
701b5663de9SDag-Erling Smørgrav static int
702b5663de9SDag-Erling Smørgrav lz_enter_override(struct local_zones* zones, char* zname, char* netblock,
703b5663de9SDag-Erling Smørgrav 	char* type, uint16_t rr_class)
704b5663de9SDag-Erling Smørgrav {
705b5663de9SDag-Erling Smørgrav 	uint8_t dname[LDNS_MAX_DOMAINLEN+1];
706b5663de9SDag-Erling Smørgrav 	size_t dname_len = sizeof(dname);
707b5663de9SDag-Erling Smørgrav 	int dname_labs;
708b5663de9SDag-Erling Smørgrav 	struct sockaddr_storage addr;
709b5663de9SDag-Erling Smørgrav 	int net;
710b5663de9SDag-Erling Smørgrav 	socklen_t addrlen;
711b5663de9SDag-Erling Smørgrav 	struct local_zone* z;
712b5663de9SDag-Erling Smørgrav 	enum localzone_type t;
713b5663de9SDag-Erling Smørgrav 
714b5663de9SDag-Erling Smørgrav 	/* parse zone name */
715b5663de9SDag-Erling Smørgrav 	if(sldns_str2wire_dname_buf(zname, dname, &dname_len) != 0) {
716b5663de9SDag-Erling Smørgrav 		log_err("cannot parse zone name in local-zone-override: %s %s",
717b5663de9SDag-Erling Smørgrav 			zname, netblock);
718b5663de9SDag-Erling Smørgrav 		return 0;
719b5663de9SDag-Erling Smørgrav 	}
720b5663de9SDag-Erling Smørgrav 	dname_labs = dname_count_labels(dname);
721b5663de9SDag-Erling Smørgrav 
722b5663de9SDag-Erling Smørgrav 	/* parse netblock */
723b5663de9SDag-Erling Smørgrav 	if(!netblockstrtoaddr(netblock, UNBOUND_DNS_PORT, &addr, &addrlen,
724b5663de9SDag-Erling Smørgrav 		&net)) {
725b5663de9SDag-Erling Smørgrav 		log_err("cannot parse netblock in local-zone-override: %s %s",
726b5663de9SDag-Erling Smørgrav 			zname, netblock);
727b5663de9SDag-Erling Smørgrav 		return 0;
728b5663de9SDag-Erling Smørgrav 	}
729b5663de9SDag-Erling Smørgrav 
730b5663de9SDag-Erling Smørgrav 	/* parse zone type */
731b5663de9SDag-Erling Smørgrav 	if(!local_zone_str2type(type, &t)) {
732b5663de9SDag-Erling Smørgrav 		log_err("cannot parse type in local-zone-override: %s %s %s",
733b5663de9SDag-Erling Smørgrav 			zname, netblock, type);
734b5663de9SDag-Erling Smørgrav 		return 0;
735b5663de9SDag-Erling Smørgrav 	}
736b5663de9SDag-Erling Smørgrav 
737b5663de9SDag-Erling Smørgrav 	/* find localzone entry */
738b5663de9SDag-Erling Smørgrav 	lock_rw_rdlock(&zones->lock);
739b5663de9SDag-Erling Smørgrav 	z = local_zones_find(zones, dname, dname_len, dname_labs, rr_class);
740b5663de9SDag-Erling Smørgrav 	if(!z) {
741b5663de9SDag-Erling Smørgrav 		lock_rw_unlock(&zones->lock);
742b5663de9SDag-Erling Smørgrav 		log_err("no local-zone for local-zone-override %s", zname);
743b5663de9SDag-Erling Smørgrav 		return 0;
744b5663de9SDag-Erling Smørgrav 	}
745b5663de9SDag-Erling Smørgrav 	lock_rw_wrlock(&z->lock);
746b5663de9SDag-Erling Smørgrav 	lock_rw_unlock(&zones->lock);
747b5663de9SDag-Erling Smørgrav 
748b5663de9SDag-Erling Smørgrav 	/* create netblock addr_tree if not present yet */
749b5663de9SDag-Erling Smørgrav 	if(!z->override_tree) {
7503005e0a3SDag-Erling Smørgrav 		z->override_tree = (struct rbtree_type*)regional_alloc_zero(
751b5663de9SDag-Erling Smørgrav 			z->region, sizeof(*z->override_tree));
752b5663de9SDag-Erling Smørgrav 		if(!z->override_tree) {
753b5663de9SDag-Erling Smørgrav 			lock_rw_unlock(&z->lock);
754b5663de9SDag-Erling Smørgrav 			log_err("out of memory");
755b5663de9SDag-Erling Smørgrav 			return 0;
756b5663de9SDag-Erling Smørgrav 		}
757b5663de9SDag-Erling Smørgrav 		addr_tree_init(z->override_tree);
758b5663de9SDag-Erling Smørgrav 	}
759b5663de9SDag-Erling Smørgrav 	/* add new elem to tree */
760b5663de9SDag-Erling Smørgrav 	if(z->override_tree) {
761b5663de9SDag-Erling Smørgrav 		struct local_zone_override* n;
762b5663de9SDag-Erling Smørgrav 		n = (struct local_zone_override*)regional_alloc_zero(
763b5663de9SDag-Erling Smørgrav 			z->region, sizeof(*n));
764b5663de9SDag-Erling Smørgrav 		if(!n) {
765b5663de9SDag-Erling Smørgrav 			lock_rw_unlock(&z->lock);
766b5663de9SDag-Erling Smørgrav 			log_err("out of memory");
767b5663de9SDag-Erling Smørgrav 			return 0;
768b5663de9SDag-Erling Smørgrav 		}
769b5663de9SDag-Erling Smørgrav 		n->type = t;
770b5663de9SDag-Erling Smørgrav 		if(!addr_tree_insert(z->override_tree,
771b5663de9SDag-Erling Smørgrav 			(struct addr_tree_node*)n, &addr, addrlen, net)) {
772b5663de9SDag-Erling Smørgrav 			lock_rw_unlock(&z->lock);
773b5663de9SDag-Erling Smørgrav 			log_err("duplicate local-zone-override %s %s",
774b5663de9SDag-Erling Smørgrav 				zname, netblock);
775b5663de9SDag-Erling Smørgrav 			return 1;
776b5663de9SDag-Erling Smørgrav 		}
777b5663de9SDag-Erling Smørgrav 	}
778b5663de9SDag-Erling Smørgrav 
779b5663de9SDag-Erling Smørgrav 	lock_rw_unlock(&z->lock);
780b5663de9SDag-Erling Smørgrav 	return 1;
781b5663de9SDag-Erling Smørgrav }
782b5663de9SDag-Erling Smørgrav 
783b7579f77SDag-Erling Smørgrav /** parse local-zone: statements */
784b7579f77SDag-Erling Smørgrav static int
785b7579f77SDag-Erling Smørgrav lz_enter_zones(struct local_zones* zones, struct config_file* cfg)
786b7579f77SDag-Erling Smørgrav {
787b7579f77SDag-Erling Smørgrav 	struct config_str2list* p;
7885469a995SCy Schubert #ifndef THREADS_DISABLED
789b7579f77SDag-Erling Smørgrav 	struct local_zone* z;
7905469a995SCy Schubert #endif
791b7579f77SDag-Erling Smørgrav 	for(p = cfg->local_zones; p; p = p->next) {
7925469a995SCy Schubert 		if(!(
7935469a995SCy Schubert #ifndef THREADS_DISABLED
7945469a995SCy Schubert 			z=
7955469a995SCy Schubert #endif
7965469a995SCy Schubert 			lz_enter_zone(zones, p->str, p->str2,
797b7579f77SDag-Erling Smørgrav 			LDNS_RR_CLASS_IN)))
798b7579f77SDag-Erling Smørgrav 			return 0;
799b7579f77SDag-Erling Smørgrav 		lock_rw_unlock(&z->lock);
800b7579f77SDag-Erling Smørgrav 	}
801b7579f77SDag-Erling Smørgrav 	return 1;
802b7579f77SDag-Erling Smørgrav }
803b7579f77SDag-Erling Smørgrav 
804b7579f77SDag-Erling Smørgrav /** lookup a zone in rbtree; exact match only; SLOW due to parse */
805b7579f77SDag-Erling Smørgrav static int
806b7579f77SDag-Erling Smørgrav lz_exists(struct local_zones* zones, const char* name)
807b7579f77SDag-Erling Smørgrav {
808b7579f77SDag-Erling Smørgrav 	struct local_zone z;
809b7579f77SDag-Erling Smørgrav 	z.node.key = &z;
810b7579f77SDag-Erling Smørgrav 	z.dclass = LDNS_RR_CLASS_IN;
811b7579f77SDag-Erling Smørgrav 	if(!parse_dname(name, &z.name, &z.namelen, &z.namelabs)) {
812b7579f77SDag-Erling Smørgrav 		log_err("bad name %s", name);
813b7579f77SDag-Erling Smørgrav 		return 0;
814b7579f77SDag-Erling Smørgrav 	}
81517d15b25SDag-Erling Smørgrav 	lock_rw_rdlock(&zones->lock);
816b7579f77SDag-Erling Smørgrav 	if(rbtree_search(&zones->ztree, &z.node)) {
81717d15b25SDag-Erling Smørgrav 		lock_rw_unlock(&zones->lock);
818b7579f77SDag-Erling Smørgrav 		free(z.name);
819b7579f77SDag-Erling Smørgrav 		return 1;
820b7579f77SDag-Erling Smørgrav 	}
82117d15b25SDag-Erling Smørgrav 	lock_rw_unlock(&zones->lock);
822b7579f77SDag-Erling Smørgrav 	free(z.name);
823b7579f77SDag-Erling Smørgrav 	return 0;
824b7579f77SDag-Erling Smørgrav }
825b7579f77SDag-Erling Smørgrav 
826b7579f77SDag-Erling Smørgrav /** lookup a zone in cfg->nodefault list */
827b7579f77SDag-Erling Smørgrav static int
828b7579f77SDag-Erling Smørgrav lz_nodefault(struct config_file* cfg, const char* name)
829b7579f77SDag-Erling Smørgrav {
830b7579f77SDag-Erling Smørgrav 	struct config_strlist* p;
831b7579f77SDag-Erling Smørgrav 	size_t len = strlen(name);
832b7579f77SDag-Erling Smørgrav 	if(len == 0) return 0;
833b7579f77SDag-Erling Smørgrav 	if(name[len-1] == '.') len--;
834b7579f77SDag-Erling Smørgrav 
835b7579f77SDag-Erling Smørgrav 	for(p = cfg->local_zones_nodefault; p; p = p->next) {
836b7579f77SDag-Erling Smørgrav 		/* compare zone name, lowercase, compare without ending . */
837b7579f77SDag-Erling Smørgrav 		if(strncasecmp(p->str, name, len) == 0 &&
838b7579f77SDag-Erling Smørgrav 			(strlen(p->str) == len || (strlen(p->str)==len+1 &&
839b7579f77SDag-Erling Smørgrav 			p->str[len] == '.')))
840b7579f77SDag-Erling Smørgrav 			return 1;
841b7579f77SDag-Erling Smørgrav 	}
842b7579f77SDag-Erling Smørgrav 	return 0;
843b7579f77SDag-Erling Smørgrav }
844b7579f77SDag-Erling Smørgrav 
845971980c3SDag-Erling Smørgrav /** enter (AS112) empty default zone */
846b7579f77SDag-Erling Smørgrav static int
847971980c3SDag-Erling Smørgrav add_empty_default(struct local_zones* zones, struct config_file* cfg,
84817d15b25SDag-Erling Smørgrav         const char* name)
849b7579f77SDag-Erling Smørgrav {
850b7579f77SDag-Erling Smørgrav 	struct local_zone* z;
851b7579f77SDag-Erling Smørgrav 	char str[1024]; /* known long enough */
852b7579f77SDag-Erling Smørgrav 	if(lz_exists(zones, name) || lz_nodefault(cfg, name))
853b7579f77SDag-Erling Smørgrav 		return 1; /* do not enter default content */
854b7579f77SDag-Erling Smørgrav 	if(!(z=lz_enter_zone(zones, name, "static", LDNS_RR_CLASS_IN)))
855b7579f77SDag-Erling Smørgrav 		return 0;
856b7579f77SDag-Erling Smørgrav 	snprintf(str, sizeof(str), "%s 10800 IN SOA localhost. "
857b7579f77SDag-Erling Smørgrav 		"nobody.invalid. 1 3600 1200 604800 10800", name);
85817d15b25SDag-Erling Smørgrav 	if(!lz_enter_rr_into_zone(z, str)) {
859b7579f77SDag-Erling Smørgrav 		lock_rw_unlock(&z->lock);
860b7579f77SDag-Erling Smørgrav 		return 0;
861b7579f77SDag-Erling Smørgrav 	}
862b7579f77SDag-Erling Smørgrav 	snprintf(str, sizeof(str), "%s 10800 IN NS localhost. ", name);
86317d15b25SDag-Erling Smørgrav 	if(!lz_enter_rr_into_zone(z, str)) {
864b7579f77SDag-Erling Smørgrav 		lock_rw_unlock(&z->lock);
865b7579f77SDag-Erling Smørgrav 		return 0;
866b7579f77SDag-Erling Smørgrav 	}
867b7579f77SDag-Erling Smørgrav 	lock_rw_unlock(&z->lock);
868b7579f77SDag-Erling Smørgrav 	return 1;
869b7579f77SDag-Erling Smørgrav }
870b7579f77SDag-Erling Smørgrav 
871b7579f77SDag-Erling Smørgrav /** enter default zones */
872c7f4d7adSDag-Erling Smørgrav int local_zone_enter_defaults(struct local_zones* zones, struct config_file* cfg)
873b7579f77SDag-Erling Smørgrav {
874b7579f77SDag-Erling Smørgrav 	struct local_zone* z;
8750de4f1bfSDag-Erling Smørgrav 	const char** zstr;
876b7579f77SDag-Erling Smørgrav 
877c7f4d7adSDag-Erling Smørgrav 	/* Do not add any default */
878c7f4d7adSDag-Erling Smørgrav 	if(cfg->local_zones_disable_default)
879c7f4d7adSDag-Erling Smørgrav 		return 1;
880c7f4d7adSDag-Erling Smørgrav 
881f61ef7f6SDag-Erling Smørgrav 	/* this list of zones is from RFC 6303 and RFC 7686 */
882b7579f77SDag-Erling Smørgrav 
883f61ef7f6SDag-Erling Smørgrav 	/* block localhost level zones first, then onion and later the LAN zones */
884c536e4dcSDag-Erling Smørgrav 
885b7579f77SDag-Erling Smørgrav 	/* localhost. zone */
886b7579f77SDag-Erling Smørgrav 	if(!lz_exists(zones, "localhost.") &&
887b7579f77SDag-Erling Smørgrav 		!lz_nodefault(cfg, "localhost.")) {
888971980c3SDag-Erling Smørgrav 		if(!(z=lz_enter_zone(zones, "localhost.", "redirect",
889b7579f77SDag-Erling Smørgrav 			LDNS_RR_CLASS_IN)) ||
89017d15b25SDag-Erling Smørgrav 		   !lz_enter_rr_into_zone(z,
891b7579f77SDag-Erling Smørgrav 			"localhost. 10800 IN NS localhost.") ||
89217d15b25SDag-Erling Smørgrav 		   !lz_enter_rr_into_zone(z,
893b7579f77SDag-Erling Smørgrav 			"localhost. 10800 IN SOA localhost. nobody.invalid. "
894b7579f77SDag-Erling Smørgrav 			"1 3600 1200 604800 10800") ||
89517d15b25SDag-Erling Smørgrav 		   !lz_enter_rr_into_zone(z,
896b7579f77SDag-Erling Smørgrav 			"localhost. 10800 IN A 127.0.0.1") ||
89717d15b25SDag-Erling Smørgrav 		   !lz_enter_rr_into_zone(z,
898b7579f77SDag-Erling Smørgrav 			"localhost. 10800 IN AAAA ::1")) {
899b7579f77SDag-Erling Smørgrav 			log_err("out of memory adding default zone");
900b7579f77SDag-Erling Smørgrav 			if(z) { lock_rw_unlock(&z->lock); }
901b7579f77SDag-Erling Smørgrav 			return 0;
902b7579f77SDag-Erling Smørgrav 		}
903b7579f77SDag-Erling Smørgrav 		lock_rw_unlock(&z->lock);
904b7579f77SDag-Erling Smørgrav 	}
905b7579f77SDag-Erling Smørgrav 	/* reverse ip4 zone */
906b7579f77SDag-Erling Smørgrav 	if(!lz_exists(zones, "127.in-addr.arpa.") &&
907b7579f77SDag-Erling Smørgrav 		!lz_nodefault(cfg, "127.in-addr.arpa.")) {
908b7579f77SDag-Erling Smørgrav 		if(!(z=lz_enter_zone(zones, "127.in-addr.arpa.", "static",
909b7579f77SDag-Erling Smørgrav 			LDNS_RR_CLASS_IN)) ||
91017d15b25SDag-Erling Smørgrav 		   !lz_enter_rr_into_zone(z,
911b7579f77SDag-Erling Smørgrav 			"127.in-addr.arpa. 10800 IN NS localhost.") ||
91217d15b25SDag-Erling Smørgrav 		   !lz_enter_rr_into_zone(z,
913b7579f77SDag-Erling Smørgrav 			"127.in-addr.arpa. 10800 IN SOA localhost. "
914b7579f77SDag-Erling Smørgrav 			"nobody.invalid. 1 3600 1200 604800 10800") ||
91517d15b25SDag-Erling Smørgrav 		   !lz_enter_rr_into_zone(z,
916b7579f77SDag-Erling Smørgrav 			"1.0.0.127.in-addr.arpa. 10800 IN PTR localhost.")) {
917b7579f77SDag-Erling Smørgrav 			log_err("out of memory adding default zone");
918b7579f77SDag-Erling Smørgrav 			if(z) { lock_rw_unlock(&z->lock); }
919b7579f77SDag-Erling Smørgrav 			return 0;
920b7579f77SDag-Erling Smørgrav 		}
921b7579f77SDag-Erling Smørgrav 		lock_rw_unlock(&z->lock);
922b7579f77SDag-Erling Smørgrav 	}
923b7579f77SDag-Erling Smørgrav 	/* reverse ip6 zone */
924b7579f77SDag-Erling Smørgrav 	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.") &&
925b7579f77SDag-Erling Smørgrav 		!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.")) {
926b7579f77SDag-Erling Smørgrav 		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",
927b7579f77SDag-Erling Smørgrav 			LDNS_RR_CLASS_IN)) ||
92817d15b25SDag-Erling Smørgrav 		   !lz_enter_rr_into_zone(z,
929b7579f77SDag-Erling Smørgrav 			"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.") ||
93017d15b25SDag-Erling Smørgrav 		   !lz_enter_rr_into_zone(z,
931b7579f77SDag-Erling Smørgrav 			"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. "
932b7579f77SDag-Erling Smørgrav 			"nobody.invalid. 1 3600 1200 604800 10800") ||
93317d15b25SDag-Erling Smørgrav 		   !lz_enter_rr_into_zone(z,
934b7579f77SDag-Erling Smørgrav 			"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.")) {
935b7579f77SDag-Erling Smørgrav 			log_err("out of memory adding default zone");
936b7579f77SDag-Erling Smørgrav 			if(z) { lock_rw_unlock(&z->lock); }
937b7579f77SDag-Erling Smørgrav 			return 0;
938b7579f77SDag-Erling Smørgrav 		}
939b7579f77SDag-Erling Smørgrav 		lock_rw_unlock(&z->lock);
940b7579f77SDag-Erling Smørgrav 	}
94124e36522SCy Schubert 	/* home.arpa. zone (RFC 8375) */
94224e36522SCy Schubert 	if(!add_empty_default(zones, cfg, "home.arpa.")) {
94324e36522SCy Schubert 		log_err("out of memory adding default zone");
94424e36522SCy Schubert 		return 0;
94524e36522SCy Schubert 	}
946*be771a7bSCy Schubert 	/* resolver.arpa. zone (RFC 9462) */
947*be771a7bSCy Schubert 	if(!add_empty_default(zones, cfg, "resolver.arpa.")) {
948*be771a7bSCy Schubert 		log_err("out of memory adding default zone");
949*be771a7bSCy Schubert 		return 0;
950*be771a7bSCy Schubert 	}
951*be771a7bSCy Schubert 	/* service.arpa. zone (draft-ietf-dnssd-srp-25) */
952*be771a7bSCy Schubert 	if(!add_empty_default(zones, cfg, "service.arpa.")) {
953*be771a7bSCy Schubert 		log_err("out of memory adding default zone");
954*be771a7bSCy Schubert 		return 0;
955*be771a7bSCy Schubert 	}
956f61ef7f6SDag-Erling Smørgrav 	/* onion. zone (RFC 7686) */
957971980c3SDag-Erling Smørgrav 	if(!add_empty_default(zones, cfg, "onion.")) {
958f61ef7f6SDag-Erling Smørgrav 		log_err("out of memory adding default zone");
959f61ef7f6SDag-Erling Smørgrav 		return 0;
960f61ef7f6SDag-Erling Smørgrav 	}
961091e9e46SCy Schubert 	/* test. zone (RFC 6761) */
962971980c3SDag-Erling Smørgrav 	if(!add_empty_default(zones, cfg, "test.")) {
963971980c3SDag-Erling Smørgrav 		log_err("out of memory adding default zone");
964971980c3SDag-Erling Smørgrav 		return 0;
965f61ef7f6SDag-Erling Smørgrav 	}
966091e9e46SCy Schubert 	/* invalid. zone (RFC 6761) */
967971980c3SDag-Erling Smørgrav 	if(!add_empty_default(zones, cfg, "invalid.")) {
968971980c3SDag-Erling Smørgrav 		log_err("out of memory adding default zone");
969971980c3SDag-Erling Smørgrav 		return 0;
970971980c3SDag-Erling Smørgrav 	}
9710de4f1bfSDag-Erling Smørgrav 	/* block AS112 zones, unless asked not to */
9720de4f1bfSDag-Erling Smørgrav 	if(!cfg->unblock_lan_zones) {
9730de4f1bfSDag-Erling Smørgrav 		for(zstr = as112_zones; *zstr; zstr++) {
974971980c3SDag-Erling Smørgrav 			if(!add_empty_default(zones, cfg, *zstr)) {
975b7579f77SDag-Erling Smørgrav 				log_err("out of memory adding default zone");
976b7579f77SDag-Erling Smørgrav 				return 0;
977b7579f77SDag-Erling Smørgrav 			}
9780de4f1bfSDag-Erling Smørgrav 		}
9790de4f1bfSDag-Erling Smørgrav 	}
980b7579f77SDag-Erling Smørgrav 	return 1;
981b7579f77SDag-Erling Smørgrav }
982b7579f77SDag-Erling Smørgrav 
983b5663de9SDag-Erling Smørgrav /** parse local-zone-override: statements */
984b5663de9SDag-Erling Smørgrav static int
985b5663de9SDag-Erling Smørgrav lz_enter_overrides(struct local_zones* zones, struct config_file* cfg)
986b5663de9SDag-Erling Smørgrav {
987b5663de9SDag-Erling Smørgrav 	struct config_str3list* p;
988b5663de9SDag-Erling Smørgrav 	for(p = cfg->local_zone_overrides; p; p = p->next) {
989b5663de9SDag-Erling Smørgrav 		if(!lz_enter_override(zones, p->str, p->str2, p->str3,
990b5663de9SDag-Erling Smørgrav 			LDNS_RR_CLASS_IN))
991b5663de9SDag-Erling Smørgrav 			return 0;
992b5663de9SDag-Erling Smørgrav 	}
993b5663de9SDag-Erling Smørgrav 	return 1;
994b5663de9SDag-Erling Smørgrav }
995b5663de9SDag-Erling Smørgrav 
99656850988SCy Schubert /* return closest parent in the tree, NULL if none */
99756850988SCy Schubert static struct local_zone* find_closest_parent(struct local_zone* curr,
99856850988SCy Schubert 	struct local_zone* prev)
999b7579f77SDag-Erling Smørgrav {
100056850988SCy Schubert 	struct local_zone* p;
1001b7579f77SDag-Erling Smørgrav 	int m;
100256850988SCy Schubert 	if(!prev || prev->dclass != curr->dclass) return NULL;
100356850988SCy Schubert 	(void)dname_lab_cmp(prev->name, prev->namelabs, curr->name,
100456850988SCy Schubert 		curr->namelabs, &m); /* we know prev is smaller */
1005b7579f77SDag-Erling Smørgrav 	/* sort order like: . com. bla.com. zwb.com. net. */
1006b7579f77SDag-Erling Smørgrav 	/* find the previous, or parent-parent-parent */
100756850988SCy Schubert 	for(p = prev; p; p = p->parent) {
1008b7579f77SDag-Erling Smørgrav 		/* looking for name with few labels, a parent */
1009b7579f77SDag-Erling Smørgrav 		if(p->namelabs <= m) {
1010b7579f77SDag-Erling Smørgrav 			/* ==: since prev matched m, this is closest*/
1011b7579f77SDag-Erling Smørgrav 			/* <: prev matches more, but is not a parent,
1012b7579f77SDag-Erling Smørgrav 			    * this one is a (grand)parent */
101356850988SCy Schubert 			return p;
1014b7579f77SDag-Erling Smørgrav 		}
101556850988SCy Schubert 	}
101656850988SCy Schubert 	return NULL;
101756850988SCy Schubert }
1018b5663de9SDag-Erling Smørgrav 
101956850988SCy Schubert /** setup parent pointers, so that a lookup can be done for closest match */
102056850988SCy Schubert void
102156850988SCy Schubert lz_init_parents(struct local_zones* zones)
102256850988SCy Schubert {
102356850988SCy Schubert 	struct local_zone* node, *prev = NULL;
102456850988SCy Schubert 	lock_rw_wrlock(&zones->lock);
102556850988SCy Schubert 	RBTREE_FOR(node, struct local_zone*, &zones->ztree) {
102656850988SCy Schubert 		lock_rw_wrlock(&node->lock);
102756850988SCy Schubert 		node->parent = find_closest_parent(node, prev);
102856850988SCy Schubert 		prev = node;
1029b5663de9SDag-Erling Smørgrav 		if(node->override_tree)
1030b5663de9SDag-Erling Smørgrav 			addr_tree_init_parents(node->override_tree);
1031b7579f77SDag-Erling Smørgrav 		lock_rw_unlock(&node->lock);
1032b7579f77SDag-Erling Smørgrav 	}
103317d15b25SDag-Erling Smørgrav 	lock_rw_unlock(&zones->lock);
1034b7579f77SDag-Erling Smørgrav }
1035b7579f77SDag-Erling Smørgrav 
1036b7579f77SDag-Erling Smørgrav /** enter implicit transparent zone for local-data: without local-zone: */
1037b7579f77SDag-Erling Smørgrav static int
1038b7579f77SDag-Erling Smørgrav lz_setup_implicit(struct local_zones* zones, struct config_file* cfg)
1039b7579f77SDag-Erling Smørgrav {
1040b7579f77SDag-Erling Smørgrav 	/* walk over all items that have no parent zone and find
1041b7579f77SDag-Erling Smørgrav 	 * the name that covers them all (could be the root) and
1042b7579f77SDag-Erling Smørgrav 	 * add that as a transparent zone */
1043b7579f77SDag-Erling Smørgrav 	struct config_strlist* p;
1044b7579f77SDag-Erling Smørgrav 	int have_name = 0;
1045b7579f77SDag-Erling Smørgrav 	int have_other_classes = 0;
1046b7579f77SDag-Erling Smørgrav 	uint16_t dclass = 0;
1047b7579f77SDag-Erling Smørgrav 	uint8_t* nm = 0;
1048b7579f77SDag-Erling Smørgrav 	size_t nmlen = 0;
1049b7579f77SDag-Erling Smørgrav 	int nmlabs = 0;
1050b7579f77SDag-Erling Smørgrav 	int match = 0; /* number of labels match count */
1051b7579f77SDag-Erling Smørgrav 
105256850988SCy Schubert 	lz_init_parents(zones); /* to enable local_zones_lookup() */
1053b7579f77SDag-Erling Smørgrav 	for(p = cfg->local_data; p; p = p->next) {
1054b7579f77SDag-Erling Smørgrav 		uint8_t* rr_name;
1055971980c3SDag-Erling Smørgrav 		uint16_t rr_class, rr_type;
1056b7579f77SDag-Erling Smørgrav 		size_t len;
1057b7579f77SDag-Erling Smørgrav 		int labs;
1058971980c3SDag-Erling Smørgrav 		if(!get_rr_nameclass(p->str, &rr_name, &rr_class, &rr_type)) {
1059b7579f77SDag-Erling Smørgrav 			log_err("Bad local-data RR %s", p->str);
1060b7579f77SDag-Erling Smørgrav 			return 0;
1061b7579f77SDag-Erling Smørgrav 		}
1062b7579f77SDag-Erling Smørgrav 		labs = dname_count_size_labels(rr_name, &len);
106317d15b25SDag-Erling Smørgrav 		lock_rw_rdlock(&zones->lock);
1064971980c3SDag-Erling Smørgrav 		if(!local_zones_lookup(zones, rr_name, len, labs, rr_class,
1065971980c3SDag-Erling Smørgrav 			rr_type)) {
10669cf5bc93SCy Schubert 			/* Check if there is a zone that this could go
10679cf5bc93SCy Schubert 			 * under but for different class; created zones are
10689cf5bc93SCy Schubert 			 * always for LDNS_RR_CLASS_IN. Create the zone with
10699cf5bc93SCy Schubert 			 * a different class but the same configured
10709cf5bc93SCy Schubert 			 * local_zone_type. */
10719cf5bc93SCy Schubert 			struct local_zone* z = local_zones_lookup(zones,
10729cf5bc93SCy Schubert 				rr_name, len, labs, LDNS_RR_CLASS_IN, rr_type);
10739cf5bc93SCy Schubert 			if(z) {
10749cf5bc93SCy Schubert 				uint8_t* name = memdup(z->name, z->namelen);
10759cf5bc93SCy Schubert 				size_t znamelen = z->namelen;
10769cf5bc93SCy Schubert 				int znamelabs = z->namelabs;
10779cf5bc93SCy Schubert 				enum localzone_type ztype = z->type;
10789cf5bc93SCy Schubert 				lock_rw_unlock(&zones->lock);
10799cf5bc93SCy Schubert 				if(!name) {
10809cf5bc93SCy Schubert 					log_err("out of memory");
10819cf5bc93SCy Schubert 					free(rr_name);
10829cf5bc93SCy Schubert 					return 0;
10839cf5bc93SCy Schubert 				}
10849cf5bc93SCy Schubert 				if(!(
10859cf5bc93SCy Schubert #ifndef THREADS_DISABLED
10869cf5bc93SCy Schubert 					z =
10879cf5bc93SCy Schubert #endif
10889cf5bc93SCy Schubert 					lz_enter_zone_dname(zones, name,
10899cf5bc93SCy Schubert 						znamelen, znamelabs,
10909cf5bc93SCy Schubert 						ztype, rr_class))) {
10919cf5bc93SCy Schubert 					free(rr_name);
10929cf5bc93SCy Schubert 					return 0;
10939cf5bc93SCy Schubert 				}
10949cf5bc93SCy Schubert 				lock_rw_unlock(&z->lock);
10959cf5bc93SCy Schubert 				free(rr_name);
10969cf5bc93SCy Schubert 				continue;
10979cf5bc93SCy Schubert 			}
1098b7579f77SDag-Erling Smørgrav 			if(!have_name) {
1099b7579f77SDag-Erling Smørgrav 				dclass = rr_class;
1100b7579f77SDag-Erling Smørgrav 				nm = rr_name;
1101b7579f77SDag-Erling Smørgrav 				nmlen = len;
1102b7579f77SDag-Erling Smørgrav 				nmlabs = labs;
1103b7579f77SDag-Erling Smørgrav 				match = labs;
1104b7579f77SDag-Erling Smørgrav 				have_name = 1;
1105b7579f77SDag-Erling Smørgrav 			} else {
1106b7579f77SDag-Erling Smørgrav 				int m;
1107b7579f77SDag-Erling Smørgrav 				if(rr_class != dclass) {
1108b7579f77SDag-Erling Smørgrav 					/* process other classes later */
1109b7579f77SDag-Erling Smørgrav 					free(rr_name);
1110b7579f77SDag-Erling Smørgrav 					have_other_classes = 1;
111117d15b25SDag-Erling Smørgrav 					lock_rw_unlock(&zones->lock);
1112b7579f77SDag-Erling Smørgrav 					continue;
1113b7579f77SDag-Erling Smørgrav 				}
1114b7579f77SDag-Erling Smørgrav 				/* find smallest shared topdomain */
1115b7579f77SDag-Erling Smørgrav 				(void)dname_lab_cmp(nm, nmlabs,
1116b7579f77SDag-Erling Smørgrav 					rr_name, labs, &m);
1117b7579f77SDag-Erling Smørgrav 				free(rr_name);
1118b7579f77SDag-Erling Smørgrav 				if(m < match)
1119b7579f77SDag-Erling Smørgrav 					match = m;
1120b7579f77SDag-Erling Smørgrav 			}
1121b7579f77SDag-Erling Smørgrav 		} else free(rr_name);
112217d15b25SDag-Erling Smørgrav 		lock_rw_unlock(&zones->lock);
1123b7579f77SDag-Erling Smørgrav 	}
1124b7579f77SDag-Erling Smørgrav 	if(have_name) {
1125b7579f77SDag-Erling Smørgrav 		uint8_t* n2;
11265469a995SCy Schubert #ifndef THREADS_DISABLED
1127b7579f77SDag-Erling Smørgrav 		struct local_zone* z;
11285469a995SCy Schubert #endif
1129b7579f77SDag-Erling Smørgrav 		/* allocate zone of smallest shared topdomain to contain em */
1130b7579f77SDag-Erling Smørgrav 		n2 = nm;
1131b7579f77SDag-Erling Smørgrav 		dname_remove_labels(&n2, &nmlen, nmlabs - match);
1132b7579f77SDag-Erling Smørgrav 		n2 = memdup(n2, nmlen);
1133b7579f77SDag-Erling Smørgrav 		free(nm);
1134b7579f77SDag-Erling Smørgrav 		if(!n2) {
1135b7579f77SDag-Erling Smørgrav 			log_err("out of memory");
1136b7579f77SDag-Erling Smørgrav 			return 0;
1137b7579f77SDag-Erling Smørgrav 		}
1138b7579f77SDag-Erling Smørgrav 		log_nametypeclass(VERB_ALGO, "implicit transparent local-zone",
1139b7579f77SDag-Erling Smørgrav 			n2, 0, dclass);
11405469a995SCy Schubert 		if(!(
11415469a995SCy Schubert #ifndef THREADS_DISABLED
11425469a995SCy Schubert 			z=
11435469a995SCy Schubert #endif
11445469a995SCy Schubert 			lz_enter_zone_dname(zones, n2, nmlen, match,
1145b7579f77SDag-Erling Smørgrav 			local_zone_transparent, dclass))) {
1146b7579f77SDag-Erling Smørgrav 			return 0;
1147b7579f77SDag-Erling Smørgrav 		}
1148b7579f77SDag-Erling Smørgrav 		lock_rw_unlock(&z->lock);
1149b7579f77SDag-Erling Smørgrav 	}
1150b7579f77SDag-Erling Smørgrav 	if(have_other_classes) {
1151b7579f77SDag-Erling Smørgrav 		/* restart to setup other class */
1152b7579f77SDag-Erling Smørgrav 		return lz_setup_implicit(zones, cfg);
1153b7579f77SDag-Erling Smørgrav 	}
1154b7579f77SDag-Erling Smørgrav 	return 1;
1155b7579f77SDag-Erling Smørgrav }
1156b7579f77SDag-Erling Smørgrav 
1157e2d15004SDag-Erling Smørgrav /** enter local-zone-tag info */
1158e2d15004SDag-Erling Smørgrav static int
1159e2d15004SDag-Erling Smørgrav lz_enter_zone_tags(struct local_zones* zones, struct config_file* cfg)
1160e2d15004SDag-Erling Smørgrav {
1161e2d15004SDag-Erling Smørgrav 	struct config_strbytelist* p;
1162e2d15004SDag-Erling Smørgrav 	int c = 0;
1163e2d15004SDag-Erling Smørgrav 	for(p = cfg->local_zone_tags; p; p = p->next) {
1164e2d15004SDag-Erling Smørgrav 		if(!lz_enter_zone_tag(zones, p->str, p->str2, p->str2len,
1165e2d15004SDag-Erling Smørgrav 			LDNS_RR_CLASS_IN))
1166e2d15004SDag-Erling Smørgrav 			return 0;
1167e2d15004SDag-Erling Smørgrav 		c++;
1168e2d15004SDag-Erling Smørgrav 	}
1169e2d15004SDag-Erling Smørgrav 	if(c) verbose(VERB_ALGO, "applied tags to %d local zones", c);
1170e2d15004SDag-Erling Smørgrav 	return 1;
1171e2d15004SDag-Erling Smørgrav }
1172e2d15004SDag-Erling Smørgrav 
1173b7579f77SDag-Erling Smørgrav /** enter auth data */
1174b7579f77SDag-Erling Smørgrav static int
117517d15b25SDag-Erling Smørgrav lz_enter_data(struct local_zones* zones, struct config_file* cfg)
1176b7579f77SDag-Erling Smørgrav {
1177b7579f77SDag-Erling Smørgrav 	struct config_strlist* p;
1178b7579f77SDag-Erling Smørgrav 	for(p = cfg->local_data; p; p = p->next) {
117917d15b25SDag-Erling Smørgrav 		if(!lz_enter_rr_str(zones, p->str))
1180b7579f77SDag-Erling Smørgrav 			return 0;
1181b7579f77SDag-Erling Smørgrav 	}
1182b7579f77SDag-Erling Smørgrav 	return 1;
1183b7579f77SDag-Erling Smørgrav }
1184b7579f77SDag-Erling Smørgrav 
1185b7579f77SDag-Erling Smørgrav /** free memory from config */
1186b7579f77SDag-Erling Smørgrav static void
1187b7579f77SDag-Erling Smørgrav lz_freeup_cfg(struct config_file* cfg)
1188b7579f77SDag-Erling Smørgrav {
1189b7579f77SDag-Erling Smørgrav 	config_deldblstrlist(cfg->local_zones);
1190b7579f77SDag-Erling Smørgrav 	cfg->local_zones = NULL;
1191b7579f77SDag-Erling Smørgrav 	config_delstrlist(cfg->local_zones_nodefault);
1192b7579f77SDag-Erling Smørgrav 	cfg->local_zones_nodefault = NULL;
1193b7579f77SDag-Erling Smørgrav 	config_delstrlist(cfg->local_data);
1194b7579f77SDag-Erling Smørgrav 	cfg->local_data = NULL;
1195b7579f77SDag-Erling Smørgrav }
1196b7579f77SDag-Erling Smørgrav 
1197b7579f77SDag-Erling Smørgrav int
1198b7579f77SDag-Erling Smørgrav local_zones_apply_cfg(struct local_zones* zones, struct config_file* cfg)
1199b7579f77SDag-Erling Smørgrav {
1200b7579f77SDag-Erling Smørgrav 	/* create zones from zone statements. */
1201b7579f77SDag-Erling Smørgrav 	if(!lz_enter_zones(zones, cfg)) {
1202b7579f77SDag-Erling Smørgrav 		return 0;
1203b7579f77SDag-Erling Smørgrav 	}
1204b7579f77SDag-Erling Smørgrav 	/* apply default zones+content (unless disabled, or overridden) */
1205c7f4d7adSDag-Erling Smørgrav 	if(!local_zone_enter_defaults(zones, cfg)) {
1206b7579f77SDag-Erling Smørgrav 		return 0;
1207b7579f77SDag-Erling Smørgrav 	}
1208b5663de9SDag-Erling Smørgrav 	/* enter local zone overrides */
1209b5663de9SDag-Erling Smørgrav 	if(!lz_enter_overrides(zones, cfg)) {
1210b5663de9SDag-Erling Smørgrav 		return 0;
1211b5663de9SDag-Erling Smørgrav 	}
1212b7579f77SDag-Erling Smørgrav 	/* create implicit transparent zone from data. */
1213b7579f77SDag-Erling Smørgrav 	if(!lz_setup_implicit(zones, cfg)) {
1214b7579f77SDag-Erling Smørgrav 		return 0;
1215b7579f77SDag-Erling Smørgrav 	}
1216b7579f77SDag-Erling Smørgrav 
1217b7579f77SDag-Erling Smørgrav 	/* setup parent ptrs for lookup during data entry */
121856850988SCy Schubert 	lz_init_parents(zones);
1219e2d15004SDag-Erling Smørgrav 	/* insert local zone tags */
1220e2d15004SDag-Erling Smørgrav 	if(!lz_enter_zone_tags(zones, cfg)) {
1221e2d15004SDag-Erling Smørgrav 		return 0;
1222e2d15004SDag-Erling Smørgrav 	}
1223b7579f77SDag-Erling Smørgrav 	/* insert local data */
122417d15b25SDag-Erling Smørgrav 	if(!lz_enter_data(zones, cfg)) {
1225b7579f77SDag-Erling Smørgrav 		return 0;
1226b7579f77SDag-Erling Smørgrav 	}
1227b7579f77SDag-Erling Smørgrav 	/* freeup memory from cfg struct. */
1228b7579f77SDag-Erling Smørgrav 	lz_freeup_cfg(cfg);
1229b7579f77SDag-Erling Smørgrav 	return 1;
1230b7579f77SDag-Erling Smørgrav }
1231b7579f77SDag-Erling Smørgrav 
1232b7579f77SDag-Erling Smørgrav struct local_zone*
1233b7579f77SDag-Erling Smørgrav local_zones_lookup(struct local_zones* zones,
1234971980c3SDag-Erling Smørgrav         uint8_t* name, size_t len, int labs, uint16_t dclass, uint16_t dtype)
1235b7579f77SDag-Erling Smørgrav {
1236b5663de9SDag-Erling Smørgrav 	return local_zones_tags_lookup(zones, name, len, labs,
1237971980c3SDag-Erling Smørgrav 		dclass, dtype, NULL, 0, 1);
1238b5663de9SDag-Erling Smørgrav }
1239b5663de9SDag-Erling Smørgrav 
1240b5663de9SDag-Erling Smørgrav struct local_zone*
1241b5663de9SDag-Erling Smørgrav local_zones_tags_lookup(struct local_zones* zones,
1242971980c3SDag-Erling Smørgrav         uint8_t* name, size_t len, int labs, uint16_t dclass, uint16_t dtype,
1243b5663de9SDag-Erling Smørgrav 	uint8_t* taglist, size_t taglen, int ignoretags)
1244b5663de9SDag-Erling Smørgrav {
12453005e0a3SDag-Erling Smørgrav 	rbnode_type* res = NULL;
1246b7579f77SDag-Erling Smørgrav 	struct local_zone *result;
1247b7579f77SDag-Erling Smørgrav 	struct local_zone key;
1248b5663de9SDag-Erling Smørgrav 	int m;
1249971980c3SDag-Erling Smørgrav 	/* for type DS use a zone higher when on a zonecut */
1250971980c3SDag-Erling Smørgrav 	if(dtype == LDNS_RR_TYPE_DS && !dname_is_root(name)) {
1251971980c3SDag-Erling Smørgrav 		dname_remove_label(&name, &len);
1252971980c3SDag-Erling Smørgrav 		labs--;
1253971980c3SDag-Erling Smørgrav 	}
1254b7579f77SDag-Erling Smørgrav 	key.node.key = &key;
1255b7579f77SDag-Erling Smørgrav 	key.dclass = dclass;
1256b7579f77SDag-Erling Smørgrav 	key.name = name;
1257b7579f77SDag-Erling Smørgrav 	key.namelen = len;
1258b7579f77SDag-Erling Smørgrav 	key.namelabs = labs;
1259b5663de9SDag-Erling Smørgrav 	rbtree_find_less_equal(&zones->ztree, &key, &res);
1260b7579f77SDag-Erling Smørgrav 	result = (struct local_zone*)res;
1261b5663de9SDag-Erling Smørgrav 	/* exact or smaller element (or no element) */
1262b7579f77SDag-Erling Smørgrav 	if(!result || result->dclass != dclass)
1263b7579f77SDag-Erling Smørgrav 		return NULL;
1264b7579f77SDag-Erling Smørgrav 	/* count number of labels matched */
1265b7579f77SDag-Erling Smørgrav 	(void)dname_lab_cmp(result->name, result->namelabs, key.name,
1266b7579f77SDag-Erling Smørgrav 		key.namelabs, &m);
1267b5663de9SDag-Erling Smørgrav 	while(result) { /* go up until qname is zone or subdomain of zone */
1268b7579f77SDag-Erling Smørgrav 		if(result->namelabs <= m)
1269b5663de9SDag-Erling Smørgrav 			if(ignoretags || !result->taglist ||
1270b5663de9SDag-Erling Smørgrav 				taglist_intersect(result->taglist,
1271b5663de9SDag-Erling Smørgrav 				result->taglen, taglist, taglen))
1272b7579f77SDag-Erling Smørgrav 				break;
1273b7579f77SDag-Erling Smørgrav 		result = result->parent;
1274b7579f77SDag-Erling Smørgrav 	}
1275b7579f77SDag-Erling Smørgrav 	return result;
1276b7579f77SDag-Erling Smørgrav }
1277b7579f77SDag-Erling Smørgrav 
1278b7579f77SDag-Erling Smørgrav struct local_zone*
1279b7579f77SDag-Erling Smørgrav local_zones_find(struct local_zones* zones,
1280b7579f77SDag-Erling Smørgrav         uint8_t* name, size_t len, int labs, uint16_t dclass)
1281b7579f77SDag-Erling Smørgrav {
1282b7579f77SDag-Erling Smørgrav 	struct local_zone key;
1283b7579f77SDag-Erling Smørgrav 	key.node.key = &key;
1284b7579f77SDag-Erling Smørgrav 	key.dclass = dclass;
1285b7579f77SDag-Erling Smørgrav 	key.name = name;
1286b7579f77SDag-Erling Smørgrav 	key.namelen = len;
1287b7579f77SDag-Erling Smørgrav 	key.namelabs = labs;
1288b7579f77SDag-Erling Smørgrav 	/* exact */
1289b7579f77SDag-Erling Smørgrav 	return (struct local_zone*)rbtree_search(&zones->ztree, &key);
1290b7579f77SDag-Erling Smørgrav }
1291b7579f77SDag-Erling Smørgrav 
1292091e9e46SCy Schubert struct local_zone*
1293091e9e46SCy Schubert local_zones_find_le(struct local_zones* zones,
1294091e9e46SCy Schubert         uint8_t* name, size_t len, int labs, uint16_t dclass,
1295091e9e46SCy Schubert 	int* exact)
1296091e9e46SCy Schubert {
1297091e9e46SCy Schubert 	struct local_zone key;
1298091e9e46SCy Schubert 	rbnode_type *node;
1299091e9e46SCy Schubert 	key.node.key = &key;
1300091e9e46SCy Schubert 	key.dclass = dclass;
1301091e9e46SCy Schubert 	key.name = name;
1302091e9e46SCy Schubert 	key.namelen = len;
1303091e9e46SCy Schubert 	key.namelabs = labs;
1304091e9e46SCy Schubert 	*exact = rbtree_find_less_equal(&zones->ztree, &key, &node);
1305091e9e46SCy Schubert 	return (struct local_zone*)node;
1306091e9e46SCy Schubert }
1307091e9e46SCy Schubert 
1308b7579f77SDag-Erling Smørgrav /** encode answer consisting of 1 rrset */
1309b7579f77SDag-Erling Smørgrav static int
1310bc892140SDag-Erling Smørgrav local_encode(struct query_info* qinfo, struct module_env* env,
13114c75e3aaSDag-Erling Smørgrav 	struct edns_data* edns, struct comm_reply* repinfo, sldns_buffer* buf,
13124c75e3aaSDag-Erling Smørgrav 	struct regional* temp, struct ub_packed_rrset_key* rrset, int ansec,
13134c75e3aaSDag-Erling Smørgrav 	int rcode)
1314b7579f77SDag-Erling Smørgrav {
1315b7579f77SDag-Erling Smørgrav 	struct reply_info rep;
1316b7579f77SDag-Erling Smørgrav 	uint16_t udpsize;
1317b7579f77SDag-Erling Smørgrav 	/* make answer with time=0 for fixed TTL values */
1318b7579f77SDag-Erling Smørgrav 	memset(&rep, 0, sizeof(rep));
1319b7579f77SDag-Erling Smørgrav 	rep.flags = (uint16_t)((BIT_QR | BIT_AA | BIT_RA) | rcode);
1320b7579f77SDag-Erling Smørgrav 	rep.qdcount = 1;
1321b7579f77SDag-Erling Smørgrav 	if(ansec)
1322b7579f77SDag-Erling Smørgrav 		rep.an_numrrsets = 1;
1323b7579f77SDag-Erling Smørgrav 	else	rep.ns_numrrsets = 1;
1324b7579f77SDag-Erling Smørgrav 	rep.rrset_count = 1;
1325b7579f77SDag-Erling Smørgrav 	rep.rrsets = &rrset;
13268f76bb7dSCy Schubert 	rep.reason_bogus = LDNS_EDE_NONE;
1327b7579f77SDag-Erling Smørgrav 	udpsize = edns->udp_size;
1328b7579f77SDag-Erling Smørgrav 	edns->edns_version = EDNS_ADVERTISED_VERSION;
1329b7579f77SDag-Erling Smørgrav 	edns->udp_size = EDNS_ADVERTISED_SIZE;
1330b7579f77SDag-Erling Smørgrav 	edns->ext_rcode = 0;
1331b7579f77SDag-Erling Smørgrav 	edns->bits &= EDNS_DO;
13324c75e3aaSDag-Erling Smørgrav 	if(!inplace_cb_reply_local_call(env, qinfo, NULL, &rep, rcode, edns,
1333f44e67d1SCy Schubert 		repinfo, temp, env->now_tv) || !reply_info_answer_encode(qinfo, &rep,
13344c75e3aaSDag-Erling Smørgrav 		*(uint16_t*)sldns_buffer_begin(buf), sldns_buffer_read_u16_at(buf, 2),
13354c75e3aaSDag-Erling Smørgrav 		buf, 0, 0, temp, udpsize, edns, (int)(edns->bits&EDNS_DO), 0)) {
1336b7579f77SDag-Erling Smørgrav 		error_encode(buf, (LDNS_RCODE_SERVFAIL|BIT_AA), qinfo,
133717d15b25SDag-Erling Smørgrav 			*(uint16_t*)sldns_buffer_begin(buf),
133817d15b25SDag-Erling Smørgrav 			sldns_buffer_read_u16_at(buf, 2), edns);
13394c75e3aaSDag-Erling Smørgrav 	}
1340b7579f77SDag-Erling Smørgrav 	return 1;
1341b7579f77SDag-Erling Smørgrav }
1342b7579f77SDag-Erling Smørgrav 
13433005e0a3SDag-Erling Smørgrav /** encode local error answer */
13443005e0a3SDag-Erling Smørgrav static void
13453005e0a3SDag-Erling Smørgrav local_error_encode(struct query_info* qinfo, struct module_env* env,
13464c75e3aaSDag-Erling Smørgrav 	struct edns_data* edns, struct comm_reply* repinfo, sldns_buffer* buf,
1347a39a5a69SCy Schubert 	struct regional* temp, int rcode, int r, int ede_code,
1348a39a5a69SCy Schubert 	const char* ede_txt)
13493005e0a3SDag-Erling Smørgrav {
13503005e0a3SDag-Erling Smørgrav 	edns->edns_version = EDNS_ADVERTISED_VERSION;
13513005e0a3SDag-Erling Smørgrav 	edns->udp_size = EDNS_ADVERTISED_SIZE;
13523005e0a3SDag-Erling Smørgrav 	edns->ext_rcode = 0;
13533005e0a3SDag-Erling Smørgrav 	edns->bits &= EDNS_DO;
13543005e0a3SDag-Erling Smørgrav 
13553005e0a3SDag-Erling Smørgrav 	if(!inplace_cb_reply_local_call(env, qinfo, NULL, NULL,
1356f44e67d1SCy Schubert 		rcode, edns, repinfo, temp, env->now_tv))
135724e36522SCy Schubert 		edns->opt_list_inplace_cb_out = NULL;
1358a39a5a69SCy Schubert 
1359a39a5a69SCy Schubert 	if(ede_code != LDNS_EDE_NONE && env->cfg->ede) {
1360a39a5a69SCy Schubert 		edns_opt_list_append_ede(&edns->opt_list_out, temp,
1361a39a5a69SCy Schubert 			ede_code, ede_txt);
1362a39a5a69SCy Schubert 	}
1363a39a5a69SCy Schubert 
13643005e0a3SDag-Erling Smørgrav 	error_encode(buf, r, qinfo, *(uint16_t*)sldns_buffer_begin(buf),
13653005e0a3SDag-Erling Smørgrav 		sldns_buffer_read_u16_at(buf, 2), edns);
13663005e0a3SDag-Erling Smørgrav }
13673005e0a3SDag-Erling Smørgrav 
1368b5663de9SDag-Erling Smørgrav /** find local data tag string match for the given type in the list */
136965b390aaSDag-Erling Smørgrav int
137065b390aaSDag-Erling Smørgrav local_data_find_tag_datas(const struct query_info* qinfo,
137165b390aaSDag-Erling Smørgrav 	struct config_strlist* list, struct ub_packed_rrset_key* r,
137265b390aaSDag-Erling Smørgrav 	struct regional* temp)
1373b5663de9SDag-Erling Smørgrav {
1374b5663de9SDag-Erling Smørgrav 	struct config_strlist* p;
1375b5663de9SDag-Erling Smørgrav 	char buf[65536];
1376b5663de9SDag-Erling Smørgrav 	uint8_t rr[LDNS_RR_BUF_SIZE];
1377b5663de9SDag-Erling Smørgrav 	size_t len;
1378b5663de9SDag-Erling Smørgrav 	int res;
1379b5663de9SDag-Erling Smørgrav 	struct packed_rrset_data* d;
1380b5663de9SDag-Erling Smørgrav 	for(p=list; p; p=p->next) {
1381bc892140SDag-Erling Smørgrav 		uint16_t rdr_type;
1382bc892140SDag-Erling Smørgrav 
1383b5663de9SDag-Erling Smørgrav 		len = sizeof(rr);
1384b5663de9SDag-Erling Smørgrav 		/* does this element match the type? */
1385b5663de9SDag-Erling Smørgrav 		snprintf(buf, sizeof(buf), ". %s", p->str);
1386b5663de9SDag-Erling Smørgrav 		res = sldns_str2wire_rr_buf(buf, rr, &len, NULL, 3600,
1387bc892140SDag-Erling Smørgrav 			NULL, 0, NULL, 0);
1388b5663de9SDag-Erling Smørgrav 		if(res != 0)
1389b5663de9SDag-Erling Smørgrav 			/* parse errors are already checked before, in
1390b5663de9SDag-Erling Smørgrav 			 * acllist check_data, skip this for robustness */
1391b5663de9SDag-Erling Smørgrav 			continue;
1392b5663de9SDag-Erling Smørgrav 		if(len < 1 /* . */ + 8 /* typeclassttl*/ + 2 /*rdatalen*/)
1393b5663de9SDag-Erling Smørgrav 			continue;
1394bc892140SDag-Erling Smørgrav 		rdr_type = sldns_wirerr_get_type(rr, len, 1);
1395bc892140SDag-Erling Smørgrav 		if(rdr_type != qinfo->qtype && rdr_type != LDNS_RR_TYPE_CNAME)
1396b5663de9SDag-Erling Smørgrav 			continue;
1397b5663de9SDag-Erling Smørgrav 
1398b5663de9SDag-Erling Smørgrav 		/* do we have entries already? if not setup key */
1399b5663de9SDag-Erling Smørgrav 		if(r->rk.dname == NULL) {
1400b5663de9SDag-Erling Smørgrav 			r->entry.key = r;
1401b5663de9SDag-Erling Smørgrav 			r->rk.dname = qinfo->qname;
1402b5663de9SDag-Erling Smørgrav 			r->rk.dname_len = qinfo->qname_len;
1403bc892140SDag-Erling Smørgrav 			r->rk.type = htons(rdr_type);
1404b5663de9SDag-Erling Smørgrav 			r->rk.rrset_class = htons(qinfo->qclass);
1405b5663de9SDag-Erling Smørgrav 			r->rk.flags = 0;
1406b5663de9SDag-Erling Smørgrav 			d = (struct packed_rrset_data*)regional_alloc_zero(
1407b5663de9SDag-Erling Smørgrav 				temp, sizeof(struct packed_rrset_data)
1408b5663de9SDag-Erling Smørgrav 				+ sizeof(size_t) + sizeof(uint8_t*) +
1409b5663de9SDag-Erling Smørgrav 				sizeof(time_t));
1410b5663de9SDag-Erling Smørgrav 			if(!d) return 0; /* out of memory */
1411b5663de9SDag-Erling Smørgrav 			r->entry.data = d;
1412b5663de9SDag-Erling Smørgrav 			d->ttl = sldns_wirerr_get_ttl(rr, len, 1);
1413b5663de9SDag-Erling Smørgrav 			d->rr_len = (size_t*)((uint8_t*)d +
1414b5663de9SDag-Erling Smørgrav 				sizeof(struct packed_rrset_data));
1415b5663de9SDag-Erling Smørgrav 			d->rr_data = (uint8_t**)&(d->rr_len[1]);
1416b5663de9SDag-Erling Smørgrav 			d->rr_ttl = (time_t*)&(d->rr_data[1]);
1417b5663de9SDag-Erling Smørgrav 		}
1418b5663de9SDag-Erling Smørgrav 		d = (struct packed_rrset_data*)r->entry.data;
1419b5663de9SDag-Erling Smørgrav 		/* add entry to the data */
1420b5663de9SDag-Erling Smørgrav 		if(d->count != 0) {
1421b5663de9SDag-Erling Smørgrav 			size_t* oldlen = d->rr_len;
1422b5663de9SDag-Erling Smørgrav 			uint8_t** olddata = d->rr_data;
1423b5663de9SDag-Erling Smørgrav 			time_t* oldttl = d->rr_ttl;
1424b5663de9SDag-Erling Smørgrav 			/* increase arrays for lookup */
1425b5663de9SDag-Erling Smørgrav 			/* this is of course slow for very many records,
1426b5663de9SDag-Erling Smørgrav 			 * but most redirects are expected with few records */
1427b5663de9SDag-Erling Smørgrav 			d->rr_len = (size_t*)regional_alloc_zero(temp,
1428b5663de9SDag-Erling Smørgrav 				(d->count+1)*sizeof(size_t));
1429b5663de9SDag-Erling Smørgrav 			d->rr_data = (uint8_t**)regional_alloc_zero(temp,
1430b5663de9SDag-Erling Smørgrav 				(d->count+1)*sizeof(uint8_t*));
1431b5663de9SDag-Erling Smørgrav 			d->rr_ttl = (time_t*)regional_alloc_zero(temp,
1432b5663de9SDag-Erling Smørgrav 				(d->count+1)*sizeof(time_t));
1433b5663de9SDag-Erling Smørgrav 			if(!d->rr_len || !d->rr_data || !d->rr_ttl)
1434b5663de9SDag-Erling Smørgrav 				return 0; /* out of memory */
1435b5663de9SDag-Erling Smørgrav 			/* first one was allocated after struct d, but new
1436b5663de9SDag-Erling Smørgrav 			 * ones get their own array increment alloc, so
1437b5663de9SDag-Erling Smørgrav 			 * copy old content */
1438b5663de9SDag-Erling Smørgrav 			memmove(d->rr_len, oldlen, d->count*sizeof(size_t));
1439b5663de9SDag-Erling Smørgrav 			memmove(d->rr_data, olddata, d->count*sizeof(uint8_t*));
1440b5663de9SDag-Erling Smørgrav 			memmove(d->rr_ttl, oldttl, d->count*sizeof(time_t));
1441b5663de9SDag-Erling Smørgrav 		}
1442b5663de9SDag-Erling Smørgrav 
1443b5663de9SDag-Erling Smørgrav 		d->rr_len[d->count] = sldns_wirerr_get_rdatalen(rr, len, 1)+2;
1444b5663de9SDag-Erling Smørgrav 		d->rr_ttl[d->count] = sldns_wirerr_get_ttl(rr, len, 1);
1445b5663de9SDag-Erling Smørgrav 		d->rr_data[d->count] = regional_alloc_init(temp,
1446b5663de9SDag-Erling Smørgrav 			sldns_wirerr_get_rdatawl(rr, len, 1),
1447b5663de9SDag-Erling Smørgrav 			d->rr_len[d->count]);
1448b5663de9SDag-Erling Smørgrav 		if(!d->rr_data[d->count])
144965b390aaSDag-Erling Smørgrav 			return 0; /* out of memory */
1450b5663de9SDag-Erling Smørgrav 		d->count++;
1451b5663de9SDag-Erling Smørgrav 	}
145265b390aaSDag-Erling Smørgrav 	if(r->rk.dname)
145365b390aaSDag-Erling Smørgrav 		return 1;
145465b390aaSDag-Erling Smørgrav 	return 0;
145565b390aaSDag-Erling Smørgrav }
145665b390aaSDag-Erling Smørgrav 
145765b390aaSDag-Erling Smørgrav static int
145865b390aaSDag-Erling Smørgrav find_tag_datas(struct query_info* qinfo, struct config_strlist* list,
145965b390aaSDag-Erling Smørgrav 	struct ub_packed_rrset_key* r, struct regional* temp)
146065b390aaSDag-Erling Smørgrav {
146165b390aaSDag-Erling Smørgrav 	int result = local_data_find_tag_datas(qinfo, list, r, temp);
146265b390aaSDag-Erling Smørgrav 
1463bc892140SDag-Erling Smørgrav 	/* If we've found a non-exact alias type of local data, make a shallow
1464bc892140SDag-Erling Smørgrav 	 * copy of the RRset and remember it in qinfo to complete the alias
1465bc892140SDag-Erling Smørgrav 	 * chain later. */
146665b390aaSDag-Erling Smørgrav 	if(result && qinfo->qtype != LDNS_RR_TYPE_CNAME &&
1467bc892140SDag-Erling Smørgrav 		r->rk.type == htons(LDNS_RR_TYPE_CNAME)) {
1468bc892140SDag-Erling Smørgrav 		qinfo->local_alias =
1469bc892140SDag-Erling Smørgrav 			regional_alloc_zero(temp, sizeof(struct local_rrset));
1470bc892140SDag-Erling Smørgrav 		if(!qinfo->local_alias)
1471bc892140SDag-Erling Smørgrav 			return 0; /* out of memory */
1472bc892140SDag-Erling Smørgrav 		qinfo->local_alias->rrset =
1473bc892140SDag-Erling Smørgrav 			regional_alloc_init(temp, r, sizeof(*r));
1474bc892140SDag-Erling Smørgrav 		if(!qinfo->local_alias->rrset)
1475bc892140SDag-Erling Smørgrav 			return 0; /* out of memory */
1476bc892140SDag-Erling Smørgrav 	}
147765b390aaSDag-Erling Smørgrav 	return result;
1478b5663de9SDag-Erling Smørgrav }
1479b5663de9SDag-Erling Smørgrav 
1480091e9e46SCy Schubert int
1481bc892140SDag-Erling Smørgrav local_data_answer(struct local_zone* z, struct module_env* env,
14824c75e3aaSDag-Erling Smørgrav 	struct query_info* qinfo, struct edns_data* edns,
14834c75e3aaSDag-Erling Smørgrav 	struct comm_reply* repinfo, sldns_buffer* buf,
1484bc892140SDag-Erling Smørgrav 	struct regional* temp, int labs, struct local_data** ldp,
1485bc892140SDag-Erling Smørgrav 	enum localzone_type lz_type, int tag, struct config_strlist** tag_datas,
1486bc892140SDag-Erling Smørgrav 	size_t tag_datas_size, char** tagname, int num_tags)
1487b7579f77SDag-Erling Smørgrav {
1488b7579f77SDag-Erling Smørgrav 	struct local_data key;
1489b7579f77SDag-Erling Smørgrav 	struct local_data* ld;
1490b7579f77SDag-Erling Smørgrav 	struct local_rrset* lr;
1491b7579f77SDag-Erling Smørgrav 	key.node.key = &key;
1492b7579f77SDag-Erling Smørgrav 	key.name = qinfo->qname;
1493b7579f77SDag-Erling Smørgrav 	key.namelen = qinfo->qname_len;
1494b7579f77SDag-Erling Smørgrav 	key.namelabs = labs;
1495e86b9096SDag-Erling Smørgrav 	if(lz_type == local_zone_redirect ||
1496e86b9096SDag-Erling Smørgrav 		lz_type == local_zone_inform_redirect) {
1497b7579f77SDag-Erling Smørgrav 		key.name = z->name;
1498b7579f77SDag-Erling Smørgrav 		key.namelen = z->namelen;
1499b7579f77SDag-Erling Smørgrav 		key.namelabs = z->namelabs;
1500b5663de9SDag-Erling Smørgrav 		if(tag != -1 && (size_t)tag<tag_datas_size && tag_datas[tag]) {
1501b5663de9SDag-Erling Smørgrav 			struct ub_packed_rrset_key r;
1502b5663de9SDag-Erling Smørgrav 			memset(&r, 0, sizeof(r));
1503bc892140SDag-Erling Smørgrav 			if(find_tag_datas(qinfo, tag_datas[tag], &r, temp)) {
1504b5663de9SDag-Erling Smørgrav 				verbose(VERB_ALGO, "redirect with tag data [%d] %s",
1505b5663de9SDag-Erling Smørgrav 					tag, (tag<num_tags?tagname[tag]:"null"));
1506bc892140SDag-Erling Smørgrav 
1507bc892140SDag-Erling Smørgrav 				/* If we found a matching alias, we should
1508bc892140SDag-Erling Smørgrav 				 * use it as part of the answer, but we can't
1509bc892140SDag-Erling Smørgrav 				 * encode it until we complete the alias
1510bc892140SDag-Erling Smørgrav 				 * chain. */
1511bc892140SDag-Erling Smørgrav 				if(qinfo->local_alias)
1512bc892140SDag-Erling Smørgrav 					return 1;
15134c75e3aaSDag-Erling Smørgrav 				return local_encode(qinfo, env, edns, repinfo, buf, temp,
1514b5663de9SDag-Erling Smørgrav 					&r, 1, LDNS_RCODE_NOERROR);
1515b5663de9SDag-Erling Smørgrav 			}
1516b5663de9SDag-Erling Smørgrav 		}
1517b7579f77SDag-Erling Smørgrav 	}
1518b7579f77SDag-Erling Smørgrav 	ld = (struct local_data*)rbtree_search(&z->data, &key.node);
1519b7579f77SDag-Erling Smørgrav 	*ldp = ld;
1520b7579f77SDag-Erling Smørgrav 	if(!ld) {
1521b7579f77SDag-Erling Smørgrav 		return 0;
1522b7579f77SDag-Erling Smørgrav 	}
1523bc892140SDag-Erling Smørgrav 	lr = local_data_find_type(ld, qinfo->qtype, 1);
1524b7579f77SDag-Erling Smørgrav 	if(!lr)
1525b7579f77SDag-Erling Smørgrav 		return 0;
1526bc892140SDag-Erling Smørgrav 
1527bc892140SDag-Erling Smørgrav 	/* Special case for alias matching.  See local_data_answer(). */
1528e86b9096SDag-Erling Smørgrav 	if((lz_type == local_zone_redirect ||
1529e86b9096SDag-Erling Smørgrav 		lz_type == local_zone_inform_redirect) &&
1530bc892140SDag-Erling Smørgrav 		qinfo->qtype != LDNS_RR_TYPE_CNAME &&
1531bc892140SDag-Erling Smørgrav 		lr->rrset->rk.type == htons(LDNS_RR_TYPE_CNAME)) {
1532091e9e46SCy Schubert 		uint8_t* ctarget;
1533091e9e46SCy Schubert 		size_t ctargetlen = 0;
1534091e9e46SCy Schubert 
1535bc892140SDag-Erling Smørgrav 		qinfo->local_alias =
1536bc892140SDag-Erling Smørgrav 			regional_alloc_zero(temp, sizeof(struct local_rrset));
1537bc892140SDag-Erling Smørgrav 		if(!qinfo->local_alias)
1538bc892140SDag-Erling Smørgrav 			return 0; /* out of memory */
1539091e9e46SCy Schubert 		qinfo->local_alias->rrset = regional_alloc_init(
1540091e9e46SCy Schubert 			temp, lr->rrset, sizeof(*lr->rrset));
1541bc892140SDag-Erling Smørgrav 		if(!qinfo->local_alias->rrset)
1542bc892140SDag-Erling Smørgrav 			return 0; /* out of memory */
1543bc892140SDag-Erling Smørgrav 		qinfo->local_alias->rrset->rk.dname = qinfo->qname;
1544bc892140SDag-Erling Smørgrav 		qinfo->local_alias->rrset->rk.dname_len = qinfo->qname_len;
1545091e9e46SCy Schubert 		get_cname_target(lr->rrset, &ctarget, &ctargetlen);
1546091e9e46SCy Schubert 		if(!ctargetlen)
1547091e9e46SCy Schubert 			return 0; /* invalid cname */
1548091e9e46SCy Schubert 		if(dname_is_wild(ctarget)) {
1549091e9e46SCy Schubert 			/* synthesize cname target */
1550b7c0c8c1SCy Schubert 			struct packed_rrset_data* d, *lr_d;
1551091e9e46SCy Schubert 			/* -3 for wildcard label and root label from qname */
1552091e9e46SCy Schubert 			size_t newtargetlen = qinfo->qname_len + ctargetlen - 3;
1553091e9e46SCy Schubert 
1554091e9e46SCy Schubert 			log_assert(ctargetlen >= 3);
1555091e9e46SCy Schubert 			log_assert(qinfo->qname_len >= 1);
1556091e9e46SCy Schubert 
1557091e9e46SCy Schubert 			if(newtargetlen > LDNS_MAX_DOMAINLEN) {
1558091e9e46SCy Schubert 				qinfo->local_alias = NULL;
1559091e9e46SCy Schubert 				local_error_encode(qinfo, env, edns, repinfo,
1560091e9e46SCy Schubert 					buf, temp, LDNS_RCODE_YXDOMAIN,
1561a39a5a69SCy Schubert 					(LDNS_RCODE_YXDOMAIN|BIT_AA),
1562a39a5a69SCy Schubert 					LDNS_EDE_OTHER,
1563a39a5a69SCy Schubert 					"DNAME expansion became too large");
1564091e9e46SCy Schubert 				return 1;
1565091e9e46SCy Schubert 			}
1566091e9e46SCy Schubert 			memset(&qinfo->local_alias->rrset->entry, 0,
1567091e9e46SCy Schubert 				sizeof(qinfo->local_alias->rrset->entry));
1568091e9e46SCy Schubert 			qinfo->local_alias->rrset->entry.key =
1569091e9e46SCy Schubert 				qinfo->local_alias->rrset;
1570091e9e46SCy Schubert 			qinfo->local_alias->rrset->entry.hash =
1571091e9e46SCy Schubert 				rrset_key_hash(&qinfo->local_alias->rrset->rk);
1572091e9e46SCy Schubert 			d = (struct packed_rrset_data*)regional_alloc_zero(temp,
1573091e9e46SCy Schubert 				sizeof(struct packed_rrset_data) + sizeof(size_t) +
1574091e9e46SCy Schubert 				sizeof(uint8_t*) + sizeof(time_t) + sizeof(uint16_t)
1575091e9e46SCy Schubert 				+ newtargetlen);
1576091e9e46SCy Schubert 			if(!d)
1577091e9e46SCy Schubert 				return 0; /* out of memory */
1578b7c0c8c1SCy Schubert 			lr_d = (struct packed_rrset_data*)lr->rrset->entry.data;
1579091e9e46SCy Schubert 			qinfo->local_alias->rrset->entry.data = d;
1580b7c0c8c1SCy Schubert 			d->ttl = lr_d->rr_ttl[0]; /* RFC6672-like behavior:
1581b7c0c8c1SCy Schubert 					    synth CNAME TTL uses original TTL*/
1582091e9e46SCy Schubert 			d->count = 1;
1583091e9e46SCy Schubert 			d->rrsig_count = 0;
1584091e9e46SCy Schubert 			d->trust = rrset_trust_ans_noAA;
1585091e9e46SCy Schubert 			d->rr_len = (size_t*)((uint8_t*)d +
1586091e9e46SCy Schubert 				sizeof(struct packed_rrset_data));
1587091e9e46SCy Schubert 			d->rr_len[0] = newtargetlen + sizeof(uint16_t);
1588091e9e46SCy Schubert 			packed_rrset_ptr_fixup(d);
1589091e9e46SCy Schubert 			d->rr_ttl[0] = d->ttl;
1590091e9e46SCy Schubert 			sldns_write_uint16(d->rr_data[0], newtargetlen);
1591091e9e46SCy Schubert 			/* write qname */
1592091e9e46SCy Schubert 			memmove(d->rr_data[0] + sizeof(uint16_t), qinfo->qname,
1593091e9e46SCy Schubert 				qinfo->qname_len - 1);
159424e36522SCy Schubert 			/* write cname target wildcard label */
1595091e9e46SCy Schubert 			memmove(d->rr_data[0] + sizeof(uint16_t) +
1596091e9e46SCy Schubert 				qinfo->qname_len - 1, ctarget + 2,
1597091e9e46SCy Schubert 				ctargetlen - 2);
1598091e9e46SCy Schubert 		}
1599bc892140SDag-Erling Smørgrav 		return 1;
1600bc892140SDag-Erling Smørgrav 	}
1601e86b9096SDag-Erling Smørgrav 	if(lz_type == local_zone_redirect ||
1602e86b9096SDag-Erling Smørgrav 		lz_type == local_zone_inform_redirect) {
1603b7579f77SDag-Erling Smørgrav 		/* convert rrset name to query name; like a wildcard */
1604b7579f77SDag-Erling Smørgrav 		struct ub_packed_rrset_key r = *lr->rrset;
1605b7579f77SDag-Erling Smørgrav 		r.rk.dname = qinfo->qname;
1606b7579f77SDag-Erling Smørgrav 		r.rk.dname_len = qinfo->qname_len;
16074c75e3aaSDag-Erling Smørgrav 		return local_encode(qinfo, env, edns, repinfo, buf, temp, &r, 1,
1608b7579f77SDag-Erling Smørgrav 			LDNS_RCODE_NOERROR);
1609b7579f77SDag-Erling Smørgrav 	}
16104c75e3aaSDag-Erling Smørgrav 	return local_encode(qinfo, env, edns, repinfo, buf, temp, lr->rrset, 1,
1611b7579f77SDag-Erling Smørgrav 		LDNS_RCODE_NOERROR);
1612b7579f77SDag-Erling Smørgrav }
1613b7579f77SDag-Erling Smørgrav 
1614b7579f77SDag-Erling Smørgrav /**
16154c75e3aaSDag-Erling Smørgrav  * See if the local zone does not cover the name, eg. the name is not
16164c75e3aaSDag-Erling Smørgrav  * in the zone and the zone is transparent */
16174c75e3aaSDag-Erling Smørgrav static int
16184c75e3aaSDag-Erling Smørgrav local_zone_does_not_cover(struct local_zone* z, struct query_info* qinfo,
16194c75e3aaSDag-Erling Smørgrav 	int labs)
16204c75e3aaSDag-Erling Smørgrav {
16214c75e3aaSDag-Erling Smørgrav 	struct local_data key;
16224c75e3aaSDag-Erling Smørgrav 	struct local_data* ld = NULL;
16234c75e3aaSDag-Erling Smørgrav 	struct local_rrset* lr = NULL;
16248f76bb7dSCy Schubert 	if(z->type == local_zone_always_transparent || z->type == local_zone_block_a)
16254c75e3aaSDag-Erling Smørgrav 		return 1;
16264c75e3aaSDag-Erling Smørgrav 	if(z->type != local_zone_transparent
16274c75e3aaSDag-Erling Smørgrav 		&& z->type != local_zone_typetransparent
16284c75e3aaSDag-Erling Smørgrav 		&& z->type != local_zone_inform)
16294c75e3aaSDag-Erling Smørgrav 		return 0;
16304c75e3aaSDag-Erling Smørgrav 	key.node.key = &key;
16314c75e3aaSDag-Erling Smørgrav 	key.name = qinfo->qname;
16324c75e3aaSDag-Erling Smørgrav 	key.namelen = qinfo->qname_len;
16334c75e3aaSDag-Erling Smørgrav 	key.namelabs = labs;
16344c75e3aaSDag-Erling Smørgrav 	ld = (struct local_data*)rbtree_search(&z->data, &key.node);
16354c75e3aaSDag-Erling Smørgrav 	if(z->type == local_zone_transparent || z->type == local_zone_inform)
16364c75e3aaSDag-Erling Smørgrav 		return (ld == NULL);
16374c75e3aaSDag-Erling Smørgrav 	if(ld)
16384c75e3aaSDag-Erling Smørgrav 		lr = local_data_find_type(ld, qinfo->qtype, 1);
16394c75e3aaSDag-Erling Smørgrav 	/* local_zone_typetransparent */
16404c75e3aaSDag-Erling Smørgrav 	return (lr == NULL);
16414c75e3aaSDag-Erling Smørgrav }
16424c75e3aaSDag-Erling Smørgrav 
164324e36522SCy Schubert static inline int
164424e36522SCy Schubert local_zone_is_udp_query(struct comm_reply* repinfo) {
164524e36522SCy Schubert 	return repinfo != NULL
164624e36522SCy Schubert 			? (repinfo->c != NULL
164724e36522SCy Schubert 				? repinfo->c->type == comm_udp
164824e36522SCy Schubert 				: 0)
164924e36522SCy Schubert 			: 0;
165024e36522SCy Schubert }
165124e36522SCy Schubert 
1652091e9e46SCy Schubert int
1653091e9e46SCy Schubert local_zones_zone_answer(struct local_zone* z, struct module_env* env,
16544c75e3aaSDag-Erling Smørgrav 	struct query_info* qinfo, struct edns_data* edns,
16554c75e3aaSDag-Erling Smørgrav 	struct comm_reply* repinfo, sldns_buffer* buf, struct regional* temp,
16564c75e3aaSDag-Erling Smørgrav 	struct local_data* ld, enum localzone_type lz_type)
1657b7579f77SDag-Erling Smørgrav {
1658091e9e46SCy Schubert 	if(lz_type == local_zone_deny ||
1659091e9e46SCy Schubert 		lz_type == local_zone_always_deny ||
1660091e9e46SCy Schubert 		lz_type == local_zone_inform_deny) {
1661b7579f77SDag-Erling Smørgrav 		/** no reply at all, signal caller by clearing buffer. */
166217d15b25SDag-Erling Smørgrav 		sldns_buffer_clear(buf);
166317d15b25SDag-Erling Smørgrav 		sldns_buffer_flip(buf);
1664b7579f77SDag-Erling Smørgrav 		return 1;
1665b5663de9SDag-Erling Smørgrav 	} else if(lz_type == local_zone_refuse
1666b5663de9SDag-Erling Smørgrav 		|| lz_type == local_zone_always_refuse) {
16674c75e3aaSDag-Erling Smørgrav 		local_error_encode(qinfo, env, edns, repinfo, buf, temp,
1668a39a5a69SCy Schubert 			LDNS_RCODE_REFUSED, (LDNS_RCODE_REFUSED|BIT_AA),
1669a39a5a69SCy Schubert 			LDNS_EDE_NONE, NULL);
1670b7579f77SDag-Erling Smørgrav 		return 1;
1671b5663de9SDag-Erling Smørgrav 	} else if(lz_type == local_zone_static ||
1672b5663de9SDag-Erling Smørgrav 		lz_type == local_zone_redirect ||
1673e86b9096SDag-Erling Smørgrav 		lz_type == local_zone_inform_redirect ||
1674091e9e46SCy Schubert 		lz_type == local_zone_always_nxdomain ||
167524e36522SCy Schubert 		lz_type == local_zone_always_nodata ||
167624e36522SCy Schubert 		(lz_type == local_zone_truncate
167724e36522SCy Schubert 			&& local_zone_is_udp_query(repinfo))) {
1678b7579f77SDag-Erling Smørgrav 		/* for static, reply nodata or nxdomain
1679b7579f77SDag-Erling Smørgrav 		 * for redirect, reply nodata */
1680b7579f77SDag-Erling Smørgrav 		/* no additional section processing,
1681b7579f77SDag-Erling Smørgrav 		 * cname, dname or wildcard processing,
1682b7579f77SDag-Erling Smørgrav 		 * or using closest match for NSEC.
1683b7579f77SDag-Erling Smørgrav 		 * or using closest match for returning delegation downwards
1684b7579f77SDag-Erling Smørgrav 		 */
1685e86b9096SDag-Erling Smørgrav 		int rcode = (ld || lz_type == local_zone_redirect ||
1686091e9e46SCy Schubert 			lz_type == local_zone_inform_redirect ||
168724e36522SCy Schubert 			lz_type == local_zone_always_nodata ||
168824e36522SCy Schubert 			lz_type == local_zone_truncate)?
1689b5663de9SDag-Erling Smørgrav 			LDNS_RCODE_NOERROR:LDNS_RCODE_NXDOMAIN;
169024e36522SCy Schubert 		rcode = (lz_type == local_zone_truncate ? (rcode|BIT_TC) : rcode);
169124e36522SCy Schubert 		if(z != NULL && z->soa && z->soa_negative)
16924c75e3aaSDag-Erling Smørgrav 			return local_encode(qinfo, env, edns, repinfo, buf, temp,
1693f44e67d1SCy Schubert 				z->soa_negative, 0, rcode);
1694a39a5a69SCy Schubert 		local_error_encode(qinfo, env, edns, repinfo, buf, temp,
1695a39a5a69SCy Schubert 			rcode, (rcode|BIT_AA), LDNS_EDE_NONE, NULL);
1696b7579f77SDag-Erling Smørgrav 		return 1;
1697b5663de9SDag-Erling Smørgrav 	} else if(lz_type == local_zone_typetransparent
1698b5663de9SDag-Erling Smørgrav 		|| lz_type == local_zone_always_transparent) {
1699b7579f77SDag-Erling Smørgrav 		/* no NODATA or NXDOMAINS for this zone type */
1700b7579f77SDag-Erling Smørgrav 		return 0;
17018f76bb7dSCy Schubert 	} else if(lz_type == local_zone_block_a) {
17028f76bb7dSCy Schubert 		/* Return NODATA for all A queries */
17038f76bb7dSCy Schubert 		if(qinfo->qtype == LDNS_RR_TYPE_A) {
17048f76bb7dSCy Schubert 			local_error_encode(qinfo, env, edns, repinfo, buf, temp,
17058f76bb7dSCy Schubert 				LDNS_RCODE_NOERROR, (LDNS_RCODE_NOERROR|BIT_AA),
17068f76bb7dSCy Schubert 				LDNS_EDE_NONE, NULL);
17078f76bb7dSCy Schubert 				return 1;
17088f76bb7dSCy Schubert 		}
17098f76bb7dSCy Schubert 
17108f76bb7dSCy Schubert 		return 0;
1711f44e67d1SCy Schubert 	} else if(lz_type == local_zone_always_null) {
1712f44e67d1SCy Schubert 		/* 0.0.0.0 or ::0 or noerror/nodata for this zone type,
1713f44e67d1SCy Schubert 		 * used for blocklists. */
1714f44e67d1SCy Schubert 		if(qinfo->qtype == LDNS_RR_TYPE_A ||
1715f44e67d1SCy Schubert 			qinfo->qtype == LDNS_RR_TYPE_AAAA) {
1716f44e67d1SCy Schubert 			struct ub_packed_rrset_key lrr;
1717f44e67d1SCy Schubert 			struct packed_rrset_data d;
1718f44e67d1SCy Schubert 			time_t rr_ttl = 3600;
1719f44e67d1SCy Schubert 			size_t rr_len = 0;
1720f44e67d1SCy Schubert 			uint8_t rr_data[2+16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
1721f44e67d1SCy Schubert 			uint8_t* rr_datas = rr_data;
1722f44e67d1SCy Schubert 			memset(&lrr, 0, sizeof(lrr));
1723f44e67d1SCy Schubert 			memset(&d, 0, sizeof(d));
1724f44e67d1SCy Schubert 			lrr.entry.data = &d;
1725f44e67d1SCy Schubert 			lrr.rk.dname = qinfo->qname;
1726f44e67d1SCy Schubert 			lrr.rk.dname_len = qinfo->qname_len;
1727f44e67d1SCy Schubert 			lrr.rk.type = htons(qinfo->qtype);
1728f44e67d1SCy Schubert 			lrr.rk.rrset_class = htons(qinfo->qclass);
1729f44e67d1SCy Schubert 			if(qinfo->qtype == LDNS_RR_TYPE_A) {
1730f44e67d1SCy Schubert 				rr_len = 4;
1731f44e67d1SCy Schubert 				sldns_write_uint16(rr_data, rr_len);
1732f44e67d1SCy Schubert 				rr_len += 2;
1733f44e67d1SCy Schubert 			} else {
1734f44e67d1SCy Schubert 				rr_len = 16;
1735f44e67d1SCy Schubert 				sldns_write_uint16(rr_data, rr_len);
1736f44e67d1SCy Schubert 				rr_len += 2;
1737f44e67d1SCy Schubert 			}
1738f44e67d1SCy Schubert 			d.ttl = rr_ttl;
1739f44e67d1SCy Schubert 			d.count = 1;
1740f44e67d1SCy Schubert 			d.rr_len = &rr_len;
1741f44e67d1SCy Schubert 			d.rr_data = &rr_datas;
1742f44e67d1SCy Schubert 			d.rr_ttl = &rr_ttl;
1743f44e67d1SCy Schubert 			return local_encode(qinfo, env, edns, repinfo, buf, temp,
1744f44e67d1SCy Schubert 				&lrr, 1, LDNS_RCODE_NOERROR);
1745f44e67d1SCy Schubert 		} else {
1746a39a5a69SCy Schubert 			/* NODATA: No EDE needed */
1747f44e67d1SCy Schubert 			local_error_encode(qinfo, env, edns, repinfo, buf,
1748f44e67d1SCy Schubert 				temp, LDNS_RCODE_NOERROR,
1749a39a5a69SCy Schubert 				(LDNS_RCODE_NOERROR|BIT_AA), -1, NULL);
1750f44e67d1SCy Schubert 		}
1751f44e67d1SCy Schubert 		return 1;
1752b7579f77SDag-Erling Smørgrav 	}
1753b5663de9SDag-Erling Smørgrav 	/* else lz_type == local_zone_transparent */
1754b7579f77SDag-Erling Smørgrav 
1755b7579f77SDag-Erling Smørgrav 	/* if the zone is transparent and the name exists, but the type
1756b7579f77SDag-Erling Smørgrav 	 * does not, then we should make this noerror/nodata */
1757b7579f77SDag-Erling Smørgrav 	if(ld && ld->rrsets) {
1758b7579f77SDag-Erling Smørgrav 		int rcode = LDNS_RCODE_NOERROR;
175924e36522SCy Schubert 		if(z != NULL && z->soa && z->soa_negative)
17604c75e3aaSDag-Erling Smørgrav 			return local_encode(qinfo, env, edns, repinfo, buf, temp,
1761f44e67d1SCy Schubert 				z->soa_negative, 0, rcode);
1762a39a5a69SCy Schubert 		/* NODATA: No EDE needed */
17634c75e3aaSDag-Erling Smørgrav 		local_error_encode(qinfo, env, edns, repinfo, buf, temp, rcode,
1764a39a5a69SCy Schubert 			(rcode|BIT_AA), LDNS_EDE_NONE, NULL);
1765b7579f77SDag-Erling Smørgrav 		return 1;
1766b7579f77SDag-Erling Smørgrav 	}
1767b7579f77SDag-Erling Smørgrav 
1768b7579f77SDag-Erling Smørgrav 	/* stop here, and resolve further on */
1769b7579f77SDag-Erling Smørgrav 	return 0;
1770b7579f77SDag-Erling Smørgrav }
1771b7579f77SDag-Erling Smørgrav 
17726480faa8SDag-Erling Smørgrav /** print log information for an inform zone query */
17736480faa8SDag-Erling Smørgrav static void
17746480faa8SDag-Erling Smørgrav lz_inform_print(struct local_zone* z, struct query_info* qinfo,
1775865f46b2SCy Schubert 	struct sockaddr_storage* addr, socklen_t addrlen)
17766480faa8SDag-Erling Smørgrav {
17776480faa8SDag-Erling Smørgrav 	char ip[128], txt[512];
1778*be771a7bSCy Schubert 	char zname[LDNS_MAX_DOMAINLEN];
1779865f46b2SCy Schubert 	uint16_t port = ntohs(((struct sockaddr_in*)addr)->sin_port);
17806480faa8SDag-Erling Smørgrav 	dname_str(z->name, zname);
1781865f46b2SCy Schubert 	addr_to_str(addr, addrlen, ip, sizeof(ip));
17824c75e3aaSDag-Erling Smørgrav 	snprintf(txt, sizeof(txt), "%s %s %s@%u", zname, local_zone_type2str(z->type), ip,
17836480faa8SDag-Erling Smørgrav 		(unsigned)port);
17840eefd307SCy Schubert 	log_nametypeclass(NO_VERBOSE, txt, qinfo->qname, qinfo->qtype, qinfo->qclass);
17856480faa8SDag-Erling Smørgrav }
17866480faa8SDag-Erling Smørgrav 
1787b5663de9SDag-Erling Smørgrav static enum localzone_type
1788b5663de9SDag-Erling Smørgrav lz_type(uint8_t *taglist, size_t taglen, uint8_t *taglist2, size_t taglen2,
1789b5663de9SDag-Erling Smørgrav 	uint8_t *tagactions, size_t tagactionssize, enum localzone_type lzt,
17903005e0a3SDag-Erling Smørgrav 	struct comm_reply* repinfo, struct rbtree_type* override_tree,
17913005e0a3SDag-Erling Smørgrav 	int* tag, char** tagname, int num_tags)
1792b5663de9SDag-Erling Smørgrav {
1793b5663de9SDag-Erling Smørgrav 	struct local_zone_override* lzo;
1794b5663de9SDag-Erling Smørgrav 	if(repinfo && override_tree) {
1795b5663de9SDag-Erling Smørgrav 		lzo = (struct local_zone_override*)addr_tree_lookup(
1796865f46b2SCy Schubert 			override_tree, &repinfo->client_addr,
1797865f46b2SCy Schubert 			repinfo->client_addrlen);
1798b5663de9SDag-Erling Smørgrav 		if(lzo && lzo->type) {
1799b5663de9SDag-Erling Smørgrav 			verbose(VERB_ALGO, "local zone override to type %s",
1800b5663de9SDag-Erling Smørgrav 				local_zone_type2str(lzo->type));
1801b5663de9SDag-Erling Smørgrav 			return lzo->type;
1802b5663de9SDag-Erling Smørgrav 		}
1803b5663de9SDag-Erling Smørgrav 	}
1804b5663de9SDag-Erling Smørgrav 	if(!taglist || !taglist2)
1805b5663de9SDag-Erling Smørgrav 		return lzt;
180665b390aaSDag-Erling Smørgrav 	return local_data_find_tag_action(taglist, taglen, taglist2, taglen2,
180765b390aaSDag-Erling Smørgrav 		tagactions, tagactionssize, lzt, tag, tagname, num_tags);
180865b390aaSDag-Erling Smørgrav }
180965b390aaSDag-Erling Smørgrav 
181065b390aaSDag-Erling Smørgrav enum localzone_type
181165b390aaSDag-Erling Smørgrav local_data_find_tag_action(const uint8_t* taglist, size_t taglen,
181265b390aaSDag-Erling Smørgrav 	const uint8_t* taglist2, size_t taglen2, const uint8_t* tagactions,
181365b390aaSDag-Erling Smørgrav 	size_t tagactionssize, enum localzone_type lzt, int* tag,
181465b390aaSDag-Erling Smørgrav 	char* const* tagname, int num_tags)
181565b390aaSDag-Erling Smørgrav {
181665b390aaSDag-Erling Smørgrav 	size_t i, j;
181765b390aaSDag-Erling Smørgrav 	uint8_t tagmatch;
181865b390aaSDag-Erling Smørgrav 
1819b5663de9SDag-Erling Smørgrav 	for(i=0; i<taglen && i<taglen2; i++) {
1820b5663de9SDag-Erling Smørgrav 		tagmatch = (taglist[i] & taglist2[i]);
1821b5663de9SDag-Erling Smørgrav 		for(j=0; j<8 && tagmatch>0; j++) {
1822b5663de9SDag-Erling Smørgrav 			if((tagmatch & 0x1)) {
1823b5663de9SDag-Erling Smørgrav 				*tag = (int)(i*8+j);
1824b5663de9SDag-Erling Smørgrav 				verbose(VERB_ALGO, "matched tag [%d] %s",
1825b5663de9SDag-Erling Smørgrav 					*tag, (*tag<num_tags?tagname[*tag]:"null"));
1826b5663de9SDag-Erling Smørgrav 				/* does this tag have a tag action? */
1827b5663de9SDag-Erling Smørgrav 				if(i*8+j < tagactionssize && tagactions
1828b5663de9SDag-Erling Smørgrav 				   && tagactions[i*8+j] != 0) {
1829b5663de9SDag-Erling Smørgrav 				  verbose(VERB_ALGO, "tag action [%d] %s to type %s",
1830b5663de9SDag-Erling Smørgrav 					*tag, (*tag<num_tags?tagname[*tag]:"null"),
1831b5663de9SDag-Erling Smørgrav 				  	local_zone_type2str(
1832b5663de9SDag-Erling Smørgrav 					(enum localzone_type)
1833b5663de9SDag-Erling Smørgrav 					tagactions[i*8+j]));
1834b5663de9SDag-Erling Smørgrav 				  return (enum localzone_type)tagactions[i*8+j];
1835b5663de9SDag-Erling Smørgrav 				}
1836b5663de9SDag-Erling Smørgrav 				return lzt;
1837b5663de9SDag-Erling Smørgrav 			}
1838b5663de9SDag-Erling Smørgrav 			tagmatch >>= 1;
1839b5663de9SDag-Erling Smørgrav 		}
1840b5663de9SDag-Erling Smørgrav 	}
1841b5663de9SDag-Erling Smørgrav 	return lzt;
1842b5663de9SDag-Erling Smørgrav }
1843b5663de9SDag-Erling Smørgrav 
1844b7579f77SDag-Erling Smørgrav int
1845bc892140SDag-Erling Smørgrav local_zones_answer(struct local_zones* zones, struct module_env* env,
1846bc892140SDag-Erling Smørgrav 	struct query_info* qinfo, struct edns_data* edns, sldns_buffer* buf,
1847bc892140SDag-Erling Smørgrav 	struct regional* temp, struct comm_reply* repinfo, uint8_t* taglist,
1848bc892140SDag-Erling Smørgrav 	size_t taglen, uint8_t* tagactions, size_t tagactionssize,
1849b5663de9SDag-Erling Smørgrav 	struct config_strlist** tag_datas, size_t tag_datas_size,
1850bc892140SDag-Erling Smørgrav 	char** tagname, int num_tags, struct view* view)
1851b7579f77SDag-Erling Smørgrav {
1852b7579f77SDag-Erling Smørgrav 	/* see if query is covered by a zone,
1853b7579f77SDag-Erling Smørgrav 	 * 	if so:	- try to match (exact) local data
1854b7579f77SDag-Erling Smørgrav 	 * 		- look at zone type for negative response. */
1855b7579f77SDag-Erling Smørgrav 	int labs = dname_count_labels(qinfo->qname);
1856b5663de9SDag-Erling Smørgrav 	struct local_data* ld = NULL;
1857bc892140SDag-Erling Smørgrav 	struct local_zone* z = NULL;
1858bc892140SDag-Erling Smørgrav 	enum localzone_type lzt = local_zone_transparent;
1859b5663de9SDag-Erling Smørgrav 	int r, tag = -1;
1860bc892140SDag-Erling Smørgrav 
1861bc892140SDag-Erling Smørgrav 	if(view) {
1862bc892140SDag-Erling Smørgrav 		lock_rw_rdlock(&view->lock);
1863bc892140SDag-Erling Smørgrav 		if(view->local_zones &&
1864bc892140SDag-Erling Smørgrav 			(z = local_zones_lookup(view->local_zones,
1865bc892140SDag-Erling Smørgrav 			qinfo->qname, qinfo->qname_len, labs,
1866971980c3SDag-Erling Smørgrav 			qinfo->qclass, qinfo->qtype))) {
1867bc892140SDag-Erling Smørgrav 			lock_rw_rdlock(&z->lock);
1868bc892140SDag-Erling Smørgrav 			lzt = z->type;
1869bc892140SDag-Erling Smørgrav 		}
187057bddd21SDag-Erling Smørgrav 		if(lzt == local_zone_noview) {
187157bddd21SDag-Erling Smørgrav 			lock_rw_unlock(&z->lock);
187257bddd21SDag-Erling Smørgrav 			z = NULL;
187357bddd21SDag-Erling Smørgrav 		}
18744c75e3aaSDag-Erling Smørgrav 		if(z && (lzt == local_zone_transparent ||
18754c75e3aaSDag-Erling Smørgrav 			lzt == local_zone_typetransparent ||
18764c75e3aaSDag-Erling Smørgrav 			lzt == local_zone_inform ||
18778f76bb7dSCy Schubert 			lzt == local_zone_always_transparent ||
18788f76bb7dSCy Schubert 			lzt == local_zone_block_a) &&
18794c75e3aaSDag-Erling Smørgrav 			local_zone_does_not_cover(z, qinfo, labs)) {
18804c75e3aaSDag-Erling Smørgrav 			lock_rw_unlock(&z->lock);
18814c75e3aaSDag-Erling Smørgrav 			z = NULL;
18824c75e3aaSDag-Erling Smørgrav 		}
1883c7f4d7adSDag-Erling Smørgrav 		if(view->local_zones && !z && !view->isfirst){
1884bc892140SDag-Erling Smørgrav 			lock_rw_unlock(&view->lock);
1885bc892140SDag-Erling Smørgrav 			return 0;
1886bc892140SDag-Erling Smørgrav 		}
18874c75e3aaSDag-Erling Smørgrav 		if(z && verbosity >= VERB_ALGO) {
1888*be771a7bSCy Schubert 			char zname[LDNS_MAX_DOMAINLEN];
18894c75e3aaSDag-Erling Smørgrav 			dname_str(z->name, zname);
18904c75e3aaSDag-Erling Smørgrav 			verbose(VERB_ALGO, "using localzone %s %s from view %s",
18914c75e3aaSDag-Erling Smørgrav 				zname, local_zone_type2str(lzt), view->name);
18924c75e3aaSDag-Erling Smørgrav 		}
1893bc892140SDag-Erling Smørgrav 		lock_rw_unlock(&view->lock);
1894bc892140SDag-Erling Smørgrav 	}
1895b7579f77SDag-Erling Smørgrav 	if(!z) {
1896bc892140SDag-Erling Smørgrav 		/* try global local_zones tree */
1897bc892140SDag-Erling Smørgrav 		lock_rw_rdlock(&zones->lock);
1898bc892140SDag-Erling Smørgrav 		if(!(z = local_zones_tags_lookup(zones, qinfo->qname,
1899971980c3SDag-Erling Smørgrav 			qinfo->qname_len, labs, qinfo->qclass, qinfo->qtype,
1900971980c3SDag-Erling Smørgrav 			taglist, taglen, 0))) {
190117d15b25SDag-Erling Smørgrav 			lock_rw_unlock(&zones->lock);
1902b7579f77SDag-Erling Smørgrav 			return 0;
1903b7579f77SDag-Erling Smørgrav 		}
1904b7579f77SDag-Erling Smørgrav 		lock_rw_rdlock(&z->lock);
1905bc892140SDag-Erling Smørgrav 		lzt = lz_type(taglist, taglen, z->taglist, z->taglen,
1906bc892140SDag-Erling Smørgrav 			tagactions, tagactionssize, z->type, repinfo,
1907bc892140SDag-Erling Smørgrav 			z->override_tree, &tag, tagname, num_tags);
190817d15b25SDag-Erling Smørgrav 		lock_rw_unlock(&zones->lock);
19094c75e3aaSDag-Erling Smørgrav 		if(z && verbosity >= VERB_ALGO) {
1910*be771a7bSCy Schubert 			char zname[LDNS_MAX_DOMAINLEN];
19114c75e3aaSDag-Erling Smørgrav 			dname_str(z->name, zname);
19124c75e3aaSDag-Erling Smørgrav 			verbose(VERB_ALGO, "using localzone %s %s", zname,
19134c75e3aaSDag-Erling Smørgrav 				local_zone_type2str(lzt));
1914bc892140SDag-Erling Smørgrav 		}
19154c75e3aaSDag-Erling Smørgrav 	}
19164c75e3aaSDag-Erling Smørgrav 	if((env->cfg->log_local_actions ||
1917e86b9096SDag-Erling Smørgrav 			lzt == local_zone_inform ||
1918e86b9096SDag-Erling Smørgrav 			lzt == local_zone_inform_deny ||
1919e86b9096SDag-Erling Smørgrav 			lzt == local_zone_inform_redirect)
192009a3aaf3SDag-Erling Smørgrav 			&& repinfo)
1921865f46b2SCy Schubert 		lz_inform_print(z, qinfo, &repinfo->client_addr,
1922865f46b2SCy Schubert 			repinfo->client_addrlen);
19236480faa8SDag-Erling Smørgrav 
1924bc892140SDag-Erling Smørgrav 	if(lzt != local_zone_always_refuse
1925bc892140SDag-Erling Smørgrav 		&& lzt != local_zone_always_transparent
19268f76bb7dSCy Schubert 		&& lzt != local_zone_block_a
1927b5663de9SDag-Erling Smørgrav 		&& lzt != local_zone_always_nxdomain
1928091e9e46SCy Schubert 		&& lzt != local_zone_always_nodata
1929091e9e46SCy Schubert 		&& lzt != local_zone_always_deny
19304c75e3aaSDag-Erling Smørgrav 		&& local_data_answer(z, env, qinfo, edns, repinfo, buf, temp, labs,
19314c75e3aaSDag-Erling Smørgrav 			&ld, lzt, tag, tag_datas, tag_datas_size, tagname, num_tags)) {
1932b7579f77SDag-Erling Smørgrav 		lock_rw_unlock(&z->lock);
1933bc892140SDag-Erling Smørgrav 		/* We should tell the caller that encode is deferred if we found
1934bc892140SDag-Erling Smørgrav 		 * a local alias. */
1935bc892140SDag-Erling Smørgrav 		return !qinfo->local_alias;
1936b7579f77SDag-Erling Smørgrav 	}
1937091e9e46SCy Schubert 	r = local_zones_zone_answer(z, env, qinfo, edns, repinfo, buf, temp, ld, lzt);
1938b7579f77SDag-Erling Smørgrav 	lock_rw_unlock(&z->lock);
1939bc892140SDag-Erling Smørgrav 	return r && !qinfo->local_alias; /* see above */
1940b7579f77SDag-Erling Smørgrav }
1941b7579f77SDag-Erling Smørgrav 
1942b7579f77SDag-Erling Smørgrav const char* local_zone_type2str(enum localzone_type t)
1943b7579f77SDag-Erling Smørgrav {
1944b7579f77SDag-Erling Smørgrav 	switch(t) {
1945bc892140SDag-Erling Smørgrav 		case local_zone_unset: return "unset";
1946b7579f77SDag-Erling Smørgrav 		case local_zone_deny: return "deny";
1947b7579f77SDag-Erling Smørgrav 		case local_zone_refuse: return "refuse";
1948b7579f77SDag-Erling Smørgrav 		case local_zone_redirect: return "redirect";
1949b7579f77SDag-Erling Smørgrav 		case local_zone_transparent: return "transparent";
1950b7579f77SDag-Erling Smørgrav 		case local_zone_typetransparent: return "typetransparent";
1951b7579f77SDag-Erling Smørgrav 		case local_zone_static: return "static";
1952b7579f77SDag-Erling Smørgrav 		case local_zone_nodefault: return "nodefault";
19536480faa8SDag-Erling Smørgrav 		case local_zone_inform: return "inform";
195409a3aaf3SDag-Erling Smørgrav 		case local_zone_inform_deny: return "inform_deny";
1955e86b9096SDag-Erling Smørgrav 		case local_zone_inform_redirect: return "inform_redirect";
1956b5663de9SDag-Erling Smørgrav 		case local_zone_always_transparent: return "always_transparent";
19578f76bb7dSCy Schubert 		case local_zone_block_a: return "block_a";
1958b5663de9SDag-Erling Smørgrav 		case local_zone_always_refuse: return "always_refuse";
1959b5663de9SDag-Erling Smørgrav 		case local_zone_always_nxdomain: return "always_nxdomain";
1960091e9e46SCy Schubert 		case local_zone_always_nodata: return "always_nodata";
1961091e9e46SCy Schubert 		case local_zone_always_deny: return "always_deny";
1962f44e67d1SCy Schubert 		case local_zone_always_null: return "always_null";
196357bddd21SDag-Erling Smørgrav 		case local_zone_noview: return "noview";
196424e36522SCy Schubert 		case local_zone_truncate: return "truncate";
1965091e9e46SCy Schubert 		case local_zone_invalid: return "invalid";
1966b7579f77SDag-Erling Smørgrav 	}
1967b7579f77SDag-Erling Smørgrav 	return "badtyped";
1968b7579f77SDag-Erling Smørgrav }
1969b7579f77SDag-Erling Smørgrav 
1970b7579f77SDag-Erling Smørgrav int local_zone_str2type(const char* type, enum localzone_type* t)
1971b7579f77SDag-Erling Smørgrav {
1972b7579f77SDag-Erling Smørgrav 	if(strcmp(type, "deny") == 0)
1973b7579f77SDag-Erling Smørgrav 		*t = local_zone_deny;
1974b7579f77SDag-Erling Smørgrav 	else if(strcmp(type, "refuse") == 0)
1975b7579f77SDag-Erling Smørgrav 		*t = local_zone_refuse;
1976b7579f77SDag-Erling Smørgrav 	else if(strcmp(type, "static") == 0)
1977b7579f77SDag-Erling Smørgrav 		*t = local_zone_static;
1978b7579f77SDag-Erling Smørgrav 	else if(strcmp(type, "transparent") == 0)
1979b7579f77SDag-Erling Smørgrav 		*t = local_zone_transparent;
1980b7579f77SDag-Erling Smørgrav 	else if(strcmp(type, "typetransparent") == 0)
1981b7579f77SDag-Erling Smørgrav 		*t = local_zone_typetransparent;
1982b7579f77SDag-Erling Smørgrav 	else if(strcmp(type, "redirect") == 0)
1983b7579f77SDag-Erling Smørgrav 		*t = local_zone_redirect;
19846480faa8SDag-Erling Smørgrav 	else if(strcmp(type, "inform") == 0)
19856480faa8SDag-Erling Smørgrav 		*t = local_zone_inform;
198609a3aaf3SDag-Erling Smørgrav 	else if(strcmp(type, "inform_deny") == 0)
198709a3aaf3SDag-Erling Smørgrav 		*t = local_zone_inform_deny;
1988e86b9096SDag-Erling Smørgrav 	else if(strcmp(type, "inform_redirect") == 0)
1989e86b9096SDag-Erling Smørgrav 		*t = local_zone_inform_redirect;
1990b5663de9SDag-Erling Smørgrav 	else if(strcmp(type, "always_transparent") == 0)
1991b5663de9SDag-Erling Smørgrav 		*t = local_zone_always_transparent;
19928f76bb7dSCy Schubert 	else if(strcmp(type, "block_a") == 0)
19938f76bb7dSCy Schubert 		*t = local_zone_block_a;
1994b5663de9SDag-Erling Smørgrav 	else if(strcmp(type, "always_refuse") == 0)
1995b5663de9SDag-Erling Smørgrav 		*t = local_zone_always_refuse;
1996b5663de9SDag-Erling Smørgrav 	else if(strcmp(type, "always_nxdomain") == 0)
1997b5663de9SDag-Erling Smørgrav 		*t = local_zone_always_nxdomain;
1998091e9e46SCy Schubert 	else if(strcmp(type, "always_nodata") == 0)
1999091e9e46SCy Schubert 		*t = local_zone_always_nodata;
2000091e9e46SCy Schubert 	else if(strcmp(type, "always_deny") == 0)
2001091e9e46SCy Schubert 		*t = local_zone_always_deny;
2002f44e67d1SCy Schubert 	else if(strcmp(type, "always_null") == 0)
2003f44e67d1SCy Schubert 		*t = local_zone_always_null;
200457bddd21SDag-Erling Smørgrav 	else if(strcmp(type, "noview") == 0)
200557bddd21SDag-Erling Smørgrav 		*t = local_zone_noview;
200624e36522SCy Schubert 	else if(strcmp(type, "truncate") == 0)
200724e36522SCy Schubert 		*t = local_zone_truncate;
2008c7f4d7adSDag-Erling Smørgrav 	else if(strcmp(type, "nodefault") == 0)
2009c7f4d7adSDag-Erling Smørgrav 		*t = local_zone_nodefault;
2010b7579f77SDag-Erling Smørgrav 	else return 0;
2011b7579f77SDag-Erling Smørgrav 	return 1;
2012b7579f77SDag-Erling Smørgrav }
2013b7579f77SDag-Erling Smørgrav 
2014b7579f77SDag-Erling Smørgrav /** iterate over the kiddies of the given name and set their parent ptr */
2015b7579f77SDag-Erling Smørgrav static void
2016b7579f77SDag-Erling Smørgrav set_kiddo_parents(struct local_zone* z, struct local_zone* match,
2017b7579f77SDag-Erling Smørgrav 	struct local_zone* newp)
2018b7579f77SDag-Erling Smørgrav {
2019b7579f77SDag-Erling Smørgrav 	/* both zones and z are locked already */
2020b7579f77SDag-Erling Smørgrav 	/* in the sorted rbtree, the kiddies of z are located after z */
2021b7579f77SDag-Erling Smørgrav 	/* z must be present in the tree */
2022b7579f77SDag-Erling Smørgrav 	struct local_zone* p = z;
2023b7579f77SDag-Erling Smørgrav 	p = (struct local_zone*)rbtree_next(&p->node);
2024b7579f77SDag-Erling Smørgrav 	while(p!=(struct local_zone*)RBTREE_NULL &&
2025b7579f77SDag-Erling Smørgrav 		p->dclass == z->dclass && dname_strict_subdomain(p->name,
2026b7579f77SDag-Erling Smørgrav 		p->namelabs, z->name, z->namelabs)) {
2027b7579f77SDag-Erling Smørgrav 		/* update parent ptr */
2028b7579f77SDag-Erling Smørgrav 		/* only when matches with existing parent pointer, so that
2029b7579f77SDag-Erling Smørgrav 		 * deeper child structures are not touched, i.e.
2030b7579f77SDag-Erling Smørgrav 		 * update of x, and a.x, b.x, f.b.x, g.b.x, c.x, y
2031b7579f77SDag-Erling Smørgrav 		 * gets to update a.x, b.x and c.x */
2032b7579f77SDag-Erling Smørgrav 		lock_rw_wrlock(&p->lock);
2033b7579f77SDag-Erling Smørgrav 		if(p->parent == match)
2034b7579f77SDag-Erling Smørgrav 			p->parent = newp;
2035b7579f77SDag-Erling Smørgrav 		lock_rw_unlock(&p->lock);
2036b7579f77SDag-Erling Smørgrav 		p = (struct local_zone*)rbtree_next(&p->node);
2037b7579f77SDag-Erling Smørgrav 	}
2038b7579f77SDag-Erling Smørgrav }
2039b7579f77SDag-Erling Smørgrav 
2040b7579f77SDag-Erling Smørgrav struct local_zone* local_zones_add_zone(struct local_zones* zones,
2041b7579f77SDag-Erling Smørgrav 	uint8_t* name, size_t len, int labs, uint16_t dclass,
2042b7579f77SDag-Erling Smørgrav 	enum localzone_type tp)
2043b7579f77SDag-Erling Smørgrav {
204456850988SCy Schubert 	int exact;
2045b7579f77SDag-Erling Smørgrav 	/* create */
204656850988SCy Schubert 	struct local_zone *prev;
2047b7579f77SDag-Erling Smørgrav 	struct local_zone* z = local_zone_create(name, len, labs, tp, dclass);
2048e2d15004SDag-Erling Smørgrav 	if(!z) {
2049e2d15004SDag-Erling Smørgrav 		free(name);
2050e2d15004SDag-Erling Smørgrav 		return NULL;
2051e2d15004SDag-Erling Smørgrav 	}
2052b7579f77SDag-Erling Smørgrav 	lock_rw_wrlock(&z->lock);
2053b7579f77SDag-Erling Smørgrav 
2054b7579f77SDag-Erling Smørgrav 	/* find the closest parent */
205556850988SCy Schubert 	prev = local_zones_find_le(zones, name, len, labs, dclass, &exact);
205656850988SCy Schubert 	if(!exact)
205756850988SCy Schubert 		z->parent = find_closest_parent(z, prev);
2058b7579f77SDag-Erling Smørgrav 
2059b7579f77SDag-Erling Smørgrav 	/* insert into the tree */
206056850988SCy Schubert 	if(exact||!rbtree_insert(&zones->ztree, &z->node)) {
2061b7579f77SDag-Erling Smørgrav 		/* duplicate entry! */
2062b7579f77SDag-Erling Smørgrav 		lock_rw_unlock(&z->lock);
2063b7579f77SDag-Erling Smørgrav 		local_zone_delete(z);
2064b7579f77SDag-Erling Smørgrav 		log_err("internal: duplicate entry in local_zones_add_zone");
2065b7579f77SDag-Erling Smørgrav 		return NULL;
2066b7579f77SDag-Erling Smørgrav 	}
2067b7579f77SDag-Erling Smørgrav 
2068b7579f77SDag-Erling Smørgrav 	/* set parent pointers right */
2069b7579f77SDag-Erling Smørgrav 	set_kiddo_parents(z, z->parent, z);
2070b7579f77SDag-Erling Smørgrav 
2071b7579f77SDag-Erling Smørgrav 	lock_rw_unlock(&z->lock);
2072b7579f77SDag-Erling Smørgrav 	return z;
2073b7579f77SDag-Erling Smørgrav }
2074b7579f77SDag-Erling Smørgrav 
2075b7579f77SDag-Erling Smørgrav void local_zones_del_zone(struct local_zones* zones, struct local_zone* z)
2076b7579f77SDag-Erling Smørgrav {
2077b7579f77SDag-Erling Smørgrav 	/* fix up parents in tree */
2078b7579f77SDag-Erling Smørgrav 	lock_rw_wrlock(&z->lock);
2079b7579f77SDag-Erling Smørgrav 	set_kiddo_parents(z, z, z->parent);
2080b7579f77SDag-Erling Smørgrav 
2081b7579f77SDag-Erling Smørgrav 	/* remove from tree */
2082b7579f77SDag-Erling Smørgrav 	(void)rbtree_delete(&zones->ztree, z);
2083b7579f77SDag-Erling Smørgrav 
2084b7579f77SDag-Erling Smørgrav 	/* delete the zone */
2085b7579f77SDag-Erling Smørgrav 	lock_rw_unlock(&z->lock);
2086b7579f77SDag-Erling Smørgrav 	local_zone_delete(z);
2087b7579f77SDag-Erling Smørgrav }
2088b7579f77SDag-Erling Smørgrav 
2089b7579f77SDag-Erling Smørgrav int
209017d15b25SDag-Erling Smørgrav local_zones_add_RR(struct local_zones* zones, const char* rr)
2091b7579f77SDag-Erling Smørgrav {
2092b7579f77SDag-Erling Smørgrav 	uint8_t* rr_name;
2093971980c3SDag-Erling Smørgrav 	uint16_t rr_class, rr_type;
2094b7579f77SDag-Erling Smørgrav 	size_t len;
2095b7579f77SDag-Erling Smørgrav 	int labs;
2096b7579f77SDag-Erling Smørgrav 	struct local_zone* z;
2097b7579f77SDag-Erling Smørgrav 	int r;
2098971980c3SDag-Erling Smørgrav 	if(!get_rr_nameclass(rr, &rr_name, &rr_class, &rr_type)) {
2099b7579f77SDag-Erling Smørgrav 		return 0;
2100b7579f77SDag-Erling Smørgrav 	}
2101b7579f77SDag-Erling Smørgrav 	labs = dname_count_size_labels(rr_name, &len);
210217d15b25SDag-Erling Smørgrav 	/* could first try readlock then get writelock if zone does not exist,
210317d15b25SDag-Erling Smørgrav 	 * but we do not add enough RRs (from multiple threads) to optimize */
210417d15b25SDag-Erling Smørgrav 	lock_rw_wrlock(&zones->lock);
2105971980c3SDag-Erling Smørgrav 	z = local_zones_lookup(zones, rr_name, len, labs, rr_class, rr_type);
2106b7579f77SDag-Erling Smørgrav 	if(!z) {
2107b7579f77SDag-Erling Smørgrav 		z = local_zones_add_zone(zones, rr_name, len, labs, rr_class,
2108b7579f77SDag-Erling Smørgrav 			local_zone_transparent);
2109b7579f77SDag-Erling Smørgrav 		if(!z) {
211017d15b25SDag-Erling Smørgrav 			lock_rw_unlock(&zones->lock);
2111b7579f77SDag-Erling Smørgrav 			return 0;
2112b7579f77SDag-Erling Smørgrav 		}
2113b7579f77SDag-Erling Smørgrav 	} else {
2114b7579f77SDag-Erling Smørgrav 		free(rr_name);
2115b7579f77SDag-Erling Smørgrav 	}
2116b7579f77SDag-Erling Smørgrav 	lock_rw_wrlock(&z->lock);
211717d15b25SDag-Erling Smørgrav 	lock_rw_unlock(&zones->lock);
211817d15b25SDag-Erling Smørgrav 	r = lz_enter_rr_into_zone(z, rr);
2119b7579f77SDag-Erling Smørgrav 	lock_rw_unlock(&z->lock);
2120b7579f77SDag-Erling Smørgrav 	return r;
2121b7579f77SDag-Erling Smørgrav }
2122b7579f77SDag-Erling Smørgrav 
2123b7579f77SDag-Erling Smørgrav /** returns true if the node is terminal so no deeper domain names exist */
2124b7579f77SDag-Erling Smørgrav static int
2125b7579f77SDag-Erling Smørgrav is_terminal(struct local_data* d)
2126b7579f77SDag-Erling Smørgrav {
2127b7579f77SDag-Erling Smørgrav 	/* for empty nonterminals, the deeper domain names are sorted
2128b7579f77SDag-Erling Smørgrav 	 * right after them, so simply check the next name in the tree
2129b7579f77SDag-Erling Smørgrav 	 */
2130b7579f77SDag-Erling Smørgrav 	struct local_data* n = (struct local_data*)rbtree_next(&d->node);
2131b7579f77SDag-Erling Smørgrav 	if(n == (struct local_data*)RBTREE_NULL)
2132b7579f77SDag-Erling Smørgrav 		return 1; /* last in tree, no deeper node */
2133b7579f77SDag-Erling Smørgrav 	if(dname_strict_subdomain(n->name, n->namelabs, d->name, d->namelabs))
2134b7579f77SDag-Erling Smørgrav 		return 0; /* there is a deeper node */
2135b7579f77SDag-Erling Smørgrav 	return 1;
2136b7579f77SDag-Erling Smørgrav }
2137b7579f77SDag-Erling Smørgrav 
2138b7579f77SDag-Erling Smørgrav /** delete empty terminals from tree when final data is deleted */
2139b7579f77SDag-Erling Smørgrav static void
2140b7579f77SDag-Erling Smørgrav del_empty_term(struct local_zone* z, struct local_data* d,
2141b7579f77SDag-Erling Smørgrav 	uint8_t* name, size_t len, int labs)
2142b7579f77SDag-Erling Smørgrav {
2143b7579f77SDag-Erling Smørgrav 	while(d && d->rrsets == NULL && is_terminal(d)) {
2144b7579f77SDag-Erling Smørgrav 		/* is this empty nonterminal? delete */
2145b7579f77SDag-Erling Smørgrav 		/* note, no memory recycling in zone region */
2146b7579f77SDag-Erling Smørgrav 		(void)rbtree_delete(&z->data, d);
2147b7579f77SDag-Erling Smørgrav 
2148b7579f77SDag-Erling Smørgrav 		/* go up and to the next label */
2149b7579f77SDag-Erling Smørgrav 		if(dname_is_root(name))
2150b7579f77SDag-Erling Smørgrav 			return;
2151b7579f77SDag-Erling Smørgrav 		dname_remove_label(&name, &len);
2152b7579f77SDag-Erling Smørgrav 		labs--;
2153091e9e46SCy Schubert 		d = local_zone_find_data(z, name, len, labs);
2154b7579f77SDag-Erling Smørgrav 	}
2155b7579f77SDag-Erling Smørgrav }
2156b7579f77SDag-Erling Smørgrav 
2157971980c3SDag-Erling Smørgrav /** find and remove type from list in domain struct */
2158971980c3SDag-Erling Smørgrav static void
2159971980c3SDag-Erling Smørgrav del_local_rrset(struct local_data* d, uint16_t dtype)
2160971980c3SDag-Erling Smørgrav {
2161971980c3SDag-Erling Smørgrav 	struct local_rrset* prev=NULL, *p=d->rrsets;
2162971980c3SDag-Erling Smørgrav 	while(p && ntohs(p->rrset->rk.type) != dtype) {
2163971980c3SDag-Erling Smørgrav 		prev = p;
2164971980c3SDag-Erling Smørgrav 		p = p->next;
2165971980c3SDag-Erling Smørgrav 	}
2166971980c3SDag-Erling Smørgrav 	if(!p)
2167971980c3SDag-Erling Smørgrav 		return; /* rrset type not found */
2168971980c3SDag-Erling Smørgrav 	/* unlink it */
2169971980c3SDag-Erling Smørgrav 	if(prev) prev->next = p->next;
2170971980c3SDag-Erling Smørgrav 	else d->rrsets = p->next;
2171971980c3SDag-Erling Smørgrav 	/* no memory recycling for zone deletions ... */
2172971980c3SDag-Erling Smørgrav }
2173971980c3SDag-Erling Smørgrav 
2174b7579f77SDag-Erling Smørgrav void local_zones_del_data(struct local_zones* zones,
2175b7579f77SDag-Erling Smørgrav 	uint8_t* name, size_t len, int labs, uint16_t dclass)
2176b7579f77SDag-Erling Smørgrav {
2177b7579f77SDag-Erling Smørgrav 	/* find zone */
2178b7579f77SDag-Erling Smørgrav 	struct local_zone* z;
2179b7579f77SDag-Erling Smørgrav 	struct local_data* d;
2180971980c3SDag-Erling Smørgrav 
2181971980c3SDag-Erling Smørgrav 	/* remove DS */
218217d15b25SDag-Erling Smørgrav 	lock_rw_rdlock(&zones->lock);
2183971980c3SDag-Erling Smørgrav 	z = local_zones_lookup(zones, name, len, labs, dclass, LDNS_RR_TYPE_DS);
2184971980c3SDag-Erling Smørgrav 	if(z) {
2185971980c3SDag-Erling Smørgrav 		lock_rw_wrlock(&z->lock);
2186091e9e46SCy Schubert 		d = local_zone_find_data(z, name, len, labs);
2187971980c3SDag-Erling Smørgrav 		if(d) {
2188971980c3SDag-Erling Smørgrav 			del_local_rrset(d, LDNS_RR_TYPE_DS);
2189971980c3SDag-Erling Smørgrav 			del_empty_term(z, d, name, len, labs);
2190971980c3SDag-Erling Smørgrav 		}
2191971980c3SDag-Erling Smørgrav 		lock_rw_unlock(&z->lock);
2192971980c3SDag-Erling Smørgrav 	}
2193971980c3SDag-Erling Smørgrav 	lock_rw_unlock(&zones->lock);
2194971980c3SDag-Erling Smørgrav 
2195971980c3SDag-Erling Smørgrav 	/* remove other types */
2196971980c3SDag-Erling Smørgrav 	lock_rw_rdlock(&zones->lock);
2197971980c3SDag-Erling Smørgrav 	z = local_zones_lookup(zones, name, len, labs, dclass, 0);
2198b7579f77SDag-Erling Smørgrav 	if(!z) {
2199b7579f77SDag-Erling Smørgrav 		/* no such zone, we're done */
220017d15b25SDag-Erling Smørgrav 		lock_rw_unlock(&zones->lock);
2201b7579f77SDag-Erling Smørgrav 		return;
2202b7579f77SDag-Erling Smørgrav 	}
2203b7579f77SDag-Erling Smørgrav 	lock_rw_wrlock(&z->lock);
220417d15b25SDag-Erling Smørgrav 	lock_rw_unlock(&zones->lock);
2205b7579f77SDag-Erling Smørgrav 
2206b7579f77SDag-Erling Smørgrav 	/* find the domain */
2207091e9e46SCy Schubert 	d = local_zone_find_data(z, name, len, labs);
2208b7579f77SDag-Erling Smørgrav 	if(d) {
2209b7579f77SDag-Erling Smørgrav 		/* no memory recycling for zone deletions ... */
2210b7579f77SDag-Erling Smørgrav 		d->rrsets = NULL;
2211b7579f77SDag-Erling Smørgrav 		/* did we delete the soa record ? */
2212f44e67d1SCy Schubert 		if(query_dname_compare(d->name, z->name) == 0) {
2213b7579f77SDag-Erling Smørgrav 			z->soa = NULL;
2214f44e67d1SCy Schubert 			z->soa_negative = NULL;
2215f44e67d1SCy Schubert 		}
2216b7579f77SDag-Erling Smørgrav 
2217b7579f77SDag-Erling Smørgrav 		/* cleanup the empty nonterminals for this name */
2218b7579f77SDag-Erling Smørgrav 		del_empty_term(z, d, name, len, labs);
2219b7579f77SDag-Erling Smørgrav 	}
2220b7579f77SDag-Erling Smørgrav 
2221b7579f77SDag-Erling Smørgrav 	lock_rw_unlock(&z->lock);
2222b7579f77SDag-Erling Smørgrav }
2223*be771a7bSCy Schubert 
2224*be771a7bSCy Schubert /** Get memory usage for local_zone */
2225*be771a7bSCy Schubert static size_t
2226*be771a7bSCy Schubert local_zone_get_mem(struct local_zone* z)
2227*be771a7bSCy Schubert {
2228*be771a7bSCy Schubert 	size_t m = sizeof(*z);
2229*be771a7bSCy Schubert 	lock_rw_rdlock(&z->lock);
2230*be771a7bSCy Schubert 	m += z->namelen + z->taglen + regional_get_mem(z->region);
2231*be771a7bSCy Schubert 	lock_rw_unlock(&z->lock);
2232*be771a7bSCy Schubert 	return m;
2233*be771a7bSCy Schubert }
2234*be771a7bSCy Schubert 
2235*be771a7bSCy Schubert size_t local_zones_get_mem(struct local_zones* zones)
2236*be771a7bSCy Schubert {
2237*be771a7bSCy Schubert 	struct local_zone* z;
2238*be771a7bSCy Schubert 	size_t m;
2239*be771a7bSCy Schubert 	if(!zones) return 0;
2240*be771a7bSCy Schubert 	m = sizeof(*zones);
2241*be771a7bSCy Schubert 	lock_rw_rdlock(&zones->lock);
2242*be771a7bSCy Schubert 	RBTREE_FOR(z, struct local_zone*, &zones->ztree) {
2243*be771a7bSCy Schubert 		m += local_zone_get_mem(z);
2244*be771a7bSCy Schubert 	}
2245*be771a7bSCy Schubert 	lock_rw_unlock(&zones->lock);
2246*be771a7bSCy Schubert 	return m;
2247*be771a7bSCy Schubert }
2248*be771a7bSCy Schubert 
2249*be771a7bSCy Schubert void local_zones_swap_tree(struct local_zones* zones, struct local_zones* data)
2250*be771a7bSCy Schubert {
2251*be771a7bSCy Schubert 	rbtree_type oldtree = zones->ztree;
2252*be771a7bSCy Schubert 	zones->ztree = data->ztree;
2253*be771a7bSCy Schubert 	data->ztree = oldtree;
2254*be771a7bSCy Schubert }
2255