xref: /freebsd/contrib/unbound/daemon/acl_list.c (revision be771a7b7f4580a30d99e41a5bb1b93a385a119d)
1b7579f77SDag-Erling Smørgrav /*
2b7579f77SDag-Erling Smørgrav  * daemon/acl_list.h - client access control storage for the server.
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 helps the server keep out queries from outside sources, that
40b7579f77SDag-Erling Smørgrav  * should not be answered.
41b7579f77SDag-Erling Smørgrav  */
42b7579f77SDag-Erling Smørgrav #include "config.h"
43b7579f77SDag-Erling Smørgrav #include "daemon/acl_list.h"
44b7579f77SDag-Erling Smørgrav #include "util/regional.h"
45b7579f77SDag-Erling Smørgrav #include "util/log.h"
46b7579f77SDag-Erling Smørgrav #include "util/config_file.h"
47b7579f77SDag-Erling Smørgrav #include "util/net_help.h"
48b5663de9SDag-Erling Smørgrav #include "services/localzone.h"
49865f46b2SCy Schubert #include "services/listen_dnsport.h"
50b5663de9SDag-Erling Smørgrav #include "sldns/str2wire.h"
51b7579f77SDag-Erling Smørgrav 
52b7579f77SDag-Erling Smørgrav struct acl_list*
53b7579f77SDag-Erling Smørgrav acl_list_create(void)
54b7579f77SDag-Erling Smørgrav {
55b7579f77SDag-Erling Smørgrav 	struct acl_list* acl = (struct acl_list*)calloc(1,
56b7579f77SDag-Erling Smørgrav 		sizeof(struct acl_list));
57b7579f77SDag-Erling Smørgrav 	if(!acl)
58b7579f77SDag-Erling Smørgrav 		return NULL;
59b7579f77SDag-Erling Smørgrav 	acl->region = regional_create();
60b7579f77SDag-Erling Smørgrav 	if(!acl->region) {
61b7579f77SDag-Erling Smørgrav 		acl_list_delete(acl);
62b7579f77SDag-Erling Smørgrav 		return NULL;
63b7579f77SDag-Erling Smørgrav 	}
64b7579f77SDag-Erling Smørgrav 	return acl;
65b7579f77SDag-Erling Smørgrav }
66b7579f77SDag-Erling Smørgrav 
67b7579f77SDag-Erling Smørgrav void
68b7579f77SDag-Erling Smørgrav acl_list_delete(struct acl_list* acl)
69b7579f77SDag-Erling Smørgrav {
70b7579f77SDag-Erling Smørgrav 	if(!acl)
71b7579f77SDag-Erling Smørgrav 		return;
72b7579f77SDag-Erling Smørgrav 	regional_destroy(acl->region);
73b7579f77SDag-Erling Smørgrav 	free(acl);
74b7579f77SDag-Erling Smørgrav }
75b7579f77SDag-Erling Smørgrav 
76b7579f77SDag-Erling Smørgrav /** insert new address into acl_list structure */
77b5663de9SDag-Erling Smørgrav static struct acl_addr*
78b7579f77SDag-Erling Smørgrav acl_list_insert(struct acl_list* acl, struct sockaddr_storage* addr,
79b7579f77SDag-Erling Smørgrav 	socklen_t addrlen, int net, enum acl_access control,
80b7579f77SDag-Erling Smørgrav 	int complain_duplicates)
81b7579f77SDag-Erling Smørgrav {
82b5663de9SDag-Erling Smørgrav 	struct acl_addr* node = regional_alloc_zero(acl->region,
83b7579f77SDag-Erling Smørgrav 		sizeof(struct acl_addr));
84b7579f77SDag-Erling Smørgrav 	if(!node)
85b5663de9SDag-Erling Smørgrav 		return NULL;
86b7579f77SDag-Erling Smørgrav 	node->control = control;
87b7579f77SDag-Erling Smørgrav 	if(!addr_tree_insert(&acl->tree, &node->node, addr, addrlen, net)) {
88b7579f77SDag-Erling Smørgrav 		if(complain_duplicates)
89b7579f77SDag-Erling Smørgrav 			verbose(VERB_QUERY, "duplicate acl address ignored.");
90b7579f77SDag-Erling Smørgrav 	}
91b5663de9SDag-Erling Smørgrav 	return node;
92b7579f77SDag-Erling Smørgrav }
93b7579f77SDag-Erling Smørgrav 
94865f46b2SCy Schubert /** parse str to acl_access enum */
95865f46b2SCy Schubert static int
96865f46b2SCy Schubert parse_acl_access(const char* str, enum acl_access* control)
97865f46b2SCy Schubert {
98865f46b2SCy Schubert 	if(strcmp(str, "allow") == 0)
99865f46b2SCy Schubert 		*control = acl_allow;
100865f46b2SCy Schubert 	else if(strcmp(str, "deny") == 0)
101865f46b2SCy Schubert 		*control = acl_deny;
102865f46b2SCy Schubert 	else if(strcmp(str, "refuse") == 0)
103865f46b2SCy Schubert 		*control = acl_refuse;
104865f46b2SCy Schubert 	else if(strcmp(str, "deny_non_local") == 0)
105865f46b2SCy Schubert 		*control = acl_deny_non_local;
106865f46b2SCy Schubert 	else if(strcmp(str, "refuse_non_local") == 0)
107865f46b2SCy Schubert 		*control = acl_refuse_non_local;
108865f46b2SCy Schubert 	else if(strcmp(str, "allow_snoop") == 0)
109865f46b2SCy Schubert 		*control = acl_allow_snoop;
110865f46b2SCy Schubert 	else if(strcmp(str, "allow_setrd") == 0)
111865f46b2SCy Schubert 		*control = acl_allow_setrd;
1128f76bb7dSCy Schubert 	else if (strcmp(str, "allow_cookie") == 0)
1138f76bb7dSCy Schubert 		*control = acl_allow_cookie;
114865f46b2SCy Schubert 	else {
115865f46b2SCy Schubert 		log_err("access control type %s unknown", str);
116865f46b2SCy Schubert 		return 0;
117865f46b2SCy Schubert 	}
118865f46b2SCy Schubert 	return 1;
119865f46b2SCy Schubert }
120865f46b2SCy Schubert 
121b7579f77SDag-Erling Smørgrav /** apply acl_list string */
122b7579f77SDag-Erling Smørgrav static int
123b7579f77SDag-Erling Smørgrav acl_list_str_cfg(struct acl_list* acl, const char* str, const char* s2,
124b7579f77SDag-Erling Smørgrav 	int complain_duplicates)
125b7579f77SDag-Erling Smørgrav {
126b7579f77SDag-Erling Smørgrav 	struct sockaddr_storage addr;
127b7579f77SDag-Erling Smørgrav 	int net;
128b7579f77SDag-Erling Smørgrav 	socklen_t addrlen;
129b7579f77SDag-Erling Smørgrav 	enum acl_access control;
130865f46b2SCy Schubert 	if(!parse_acl_access(s2, &control)) {
131b7579f77SDag-Erling Smørgrav 		return 0;
132b7579f77SDag-Erling Smørgrav 	}
133b7579f77SDag-Erling Smørgrav 	if(!netblockstrtoaddr(str, UNBOUND_DNS_PORT, &addr, &addrlen, &net)) {
134b7579f77SDag-Erling Smørgrav 		log_err("cannot parse access control: %s %s", str, s2);
135b7579f77SDag-Erling Smørgrav 		return 0;
136b7579f77SDag-Erling Smørgrav 	}
137b7579f77SDag-Erling Smørgrav 	if(!acl_list_insert(acl, &addr, addrlen, net, control,
138b7579f77SDag-Erling Smørgrav 		complain_duplicates)) {
139b7579f77SDag-Erling Smørgrav 		log_err("out of memory");
140b7579f77SDag-Erling Smørgrav 		return 0;
141b7579f77SDag-Erling Smørgrav 	}
142b7579f77SDag-Erling Smørgrav 	return 1;
143b7579f77SDag-Erling Smørgrav }
144b7579f77SDag-Erling Smørgrav 
145b5663de9SDag-Erling Smørgrav /** find or create node (NULL on parse or error) */
146b5663de9SDag-Erling Smørgrav static struct acl_addr*
147865f46b2SCy Schubert acl_find_or_create_str2addr(struct acl_list* acl, const char* str,
148865f46b2SCy Schubert 	int is_interface, int port)
149b5663de9SDag-Erling Smørgrav {
150b5663de9SDag-Erling Smørgrav 	struct acl_addr* node;
151b5663de9SDag-Erling Smørgrav 	struct sockaddr_storage addr;
152b5663de9SDag-Erling Smørgrav 	socklen_t addrlen;
153865f46b2SCy Schubert 	int net = (str_is_ip6(str)?128:32);
154865f46b2SCy Schubert 	if(is_interface) {
155865f46b2SCy Schubert 		if(!extstrtoaddr(str, &addr, &addrlen, port)) {
156865f46b2SCy Schubert 			log_err("cannot parse interface: %s", str);
157865f46b2SCy Schubert 			return NULL;
158865f46b2SCy Schubert 		}
159865f46b2SCy Schubert 	} else {
160b5663de9SDag-Erling Smørgrav 		if(!netblockstrtoaddr(str, UNBOUND_DNS_PORT, &addr, &addrlen, &net)) {
161b5663de9SDag-Erling Smørgrav 			log_err("cannot parse netblock: %s", str);
162b5663de9SDag-Erling Smørgrav 			return NULL;
163b5663de9SDag-Erling Smørgrav 		}
164865f46b2SCy Schubert 	}
165b5663de9SDag-Erling Smørgrav 	/* find or create node */
166b5663de9SDag-Erling Smørgrav 	if(!(node=(struct acl_addr*)addr_tree_find(&acl->tree, &addr,
167865f46b2SCy Schubert 		addrlen, net)) && !is_interface) {
168b5663de9SDag-Erling Smørgrav 		/* create node, type 'allow' since otherwise tags are
169b5663de9SDag-Erling Smørgrav 		 * pointless, can override with specific access-control: cfg */
170b5663de9SDag-Erling Smørgrav 		if(!(node=(struct acl_addr*)acl_list_insert(acl, &addr,
171b5663de9SDag-Erling Smørgrav 			addrlen, net, acl_allow, 1))) {
172b5663de9SDag-Erling Smørgrav 			log_err("out of memory");
173b5663de9SDag-Erling Smørgrav 			return NULL;
174b5663de9SDag-Erling Smørgrav 		}
175b5663de9SDag-Erling Smørgrav 	}
176b5663de9SDag-Erling Smørgrav 	return node;
177b5663de9SDag-Erling Smørgrav }
178b5663de9SDag-Erling Smørgrav 
179865f46b2SCy Schubert /** find or create node (NULL on error) */
180865f46b2SCy Schubert static struct acl_addr*
181865f46b2SCy Schubert acl_find_or_create(struct acl_list* acl, struct sockaddr_storage* addr,
182865f46b2SCy Schubert 	socklen_t addrlen, enum acl_access control)
183865f46b2SCy Schubert {
184865f46b2SCy Schubert 	struct acl_addr* node;
185865f46b2SCy Schubert 	int net = (addr_is_ip6(addr, addrlen)?128:32);
186865f46b2SCy Schubert 	/* find or create node */
187865f46b2SCy Schubert 	if(!(node=(struct acl_addr*)addr_tree_find(&acl->tree, addr,
188865f46b2SCy Schubert 		addrlen, net))) {
189865f46b2SCy Schubert 		/* create node;
190865f46b2SCy Schubert 		 * can override with specific access-control: cfg */
191865f46b2SCy Schubert 		if(!(node=(struct acl_addr*)acl_list_insert(acl, addr,
192865f46b2SCy Schubert 			addrlen, net, control, 1))) {
193865f46b2SCy Schubert 			log_err("out of memory");
194865f46b2SCy Schubert 			return NULL;
195865f46b2SCy Schubert 		}
196865f46b2SCy Schubert 	}
197865f46b2SCy Schubert 	return node;
198865f46b2SCy Schubert }
199865f46b2SCy Schubert 
200865f46b2SCy Schubert /** apply acl_interface string */
201865f46b2SCy Schubert static int
202865f46b2SCy Schubert acl_interface_str_cfg(struct acl_list* acl_interface, const char* iface,
203865f46b2SCy Schubert 	const char* s2, int port)
204865f46b2SCy Schubert {
205865f46b2SCy Schubert 	struct acl_addr* node;
206865f46b2SCy Schubert 	enum acl_access control;
207865f46b2SCy Schubert 	if(!parse_acl_access(s2, &control)) {
208865f46b2SCy Schubert 		return 0;
209865f46b2SCy Schubert 	}
210865f46b2SCy Schubert 	if(!(node=acl_find_or_create_str2addr(acl_interface, iface, 1, port))) {
211865f46b2SCy Schubert 		log_err("cannot update ACL on non-configured interface: %s %d",
212865f46b2SCy Schubert 			iface, port);
213865f46b2SCy Schubert 		return 0;
214865f46b2SCy Schubert 	}
215865f46b2SCy Schubert 	node->control = control;
216865f46b2SCy Schubert 	return 1;
217865f46b2SCy Schubert }
218865f46b2SCy Schubert 
219865f46b2SCy Schubert struct acl_addr*
220865f46b2SCy Schubert acl_interface_insert(struct acl_list* acl_interface,
221865f46b2SCy Schubert 	struct sockaddr_storage* addr, socklen_t addrlen,
222865f46b2SCy Schubert 	enum acl_access control)
223865f46b2SCy Schubert {
224*be771a7bSCy Schubert 	struct acl_addr* node = acl_find_or_create(acl_interface, addr, addrlen, control);
225*be771a7bSCy Schubert 	node->is_interface = 1;
226*be771a7bSCy Schubert 	return node;
227865f46b2SCy Schubert }
228865f46b2SCy Schubert 
229b5663de9SDag-Erling Smørgrav /** apply acl_tag string */
230b5663de9SDag-Erling Smørgrav static int
231b5663de9SDag-Erling Smørgrav acl_list_tags_cfg(struct acl_list* acl, const char* str, uint8_t* bitmap,
232865f46b2SCy Schubert 	size_t bitmaplen, int is_interface, int port)
233b5663de9SDag-Erling Smørgrav {
234b5663de9SDag-Erling Smørgrav 	struct acl_addr* node;
235865f46b2SCy Schubert 	if(!(node=acl_find_or_create_str2addr(acl, str, is_interface, port))) {
236865f46b2SCy Schubert 		if(is_interface)
237865f46b2SCy Schubert 			log_err("non-configured interface: %s", str);
238b5663de9SDag-Erling Smørgrav 		return 0;
239865f46b2SCy Schubert 	}
240b5663de9SDag-Erling Smørgrav 	node->taglen = bitmaplen;
241b5663de9SDag-Erling Smørgrav 	node->taglist = regional_alloc_init(acl->region, bitmap, bitmaplen);
242b5663de9SDag-Erling Smørgrav 	if(!node->taglist) {
243b5663de9SDag-Erling Smørgrav 		log_err("out of memory");
244b5663de9SDag-Erling Smørgrav 		return 0;
245b5663de9SDag-Erling Smørgrav 	}
246b5663de9SDag-Erling Smørgrav 	return 1;
247b5663de9SDag-Erling Smørgrav }
248b5663de9SDag-Erling Smørgrav 
249bc892140SDag-Erling Smørgrav /** apply acl_view string */
250bc892140SDag-Erling Smørgrav static int
251bc892140SDag-Erling Smørgrav acl_list_view_cfg(struct acl_list* acl, const char* str, const char* str2,
252865f46b2SCy Schubert 	struct views* vs, int is_interface, int port)
253bc892140SDag-Erling Smørgrav {
254bc892140SDag-Erling Smørgrav 	struct acl_addr* node;
255865f46b2SCy Schubert 	if(!(node=acl_find_or_create_str2addr(acl, str, is_interface, port))) {
256865f46b2SCy Schubert 		if(is_interface)
257865f46b2SCy Schubert 			log_err("non-configured interface: %s", str);
258bc892140SDag-Erling Smørgrav 		return 0;
259865f46b2SCy Schubert 	}
260bc892140SDag-Erling Smørgrav 	node->view = views_find_view(vs, str2, 0 /* get read lock*/);
261bc892140SDag-Erling Smørgrav 	if(!node->view) {
262bc892140SDag-Erling Smørgrav 		log_err("no view with name: %s", str2);
263bc892140SDag-Erling Smørgrav 		return 0;
264bc892140SDag-Erling Smørgrav 	}
265bc892140SDag-Erling Smørgrav 	lock_rw_unlock(&node->view->lock);
266bc892140SDag-Erling Smørgrav 	return 1;
267bc892140SDag-Erling Smørgrav }
268bc892140SDag-Erling Smørgrav 
269b5663de9SDag-Erling Smørgrav /** apply acl_tag_action string */
270b5663de9SDag-Erling Smørgrav static int
271b5663de9SDag-Erling Smørgrav acl_list_tag_action_cfg(struct acl_list* acl, struct config_file* cfg,
272865f46b2SCy Schubert 	const char* str, const char* tag, const char* action,
273865f46b2SCy Schubert 	int is_interface, int port)
274b5663de9SDag-Erling Smørgrav {
275b5663de9SDag-Erling Smørgrav 	struct acl_addr* node;
276b5663de9SDag-Erling Smørgrav 	int tagid;
277b5663de9SDag-Erling Smørgrav 	enum localzone_type t;
278865f46b2SCy Schubert 	if(!(node=acl_find_or_create_str2addr(acl, str, is_interface, port))) {
279865f46b2SCy Schubert 		if(is_interface)
280865f46b2SCy Schubert 			log_err("non-configured interface: %s", str);
281b5663de9SDag-Erling Smørgrav 		return 0;
282865f46b2SCy Schubert 	}
283b5663de9SDag-Erling Smørgrav 	/* allocate array if not yet */
284b5663de9SDag-Erling Smørgrav 	if(!node->tag_actions) {
285b5663de9SDag-Erling Smørgrav 		node->tag_actions = (uint8_t*)regional_alloc_zero(acl->region,
286b5663de9SDag-Erling Smørgrav 			sizeof(*node->tag_actions)*cfg->num_tags);
287b5663de9SDag-Erling Smørgrav 		if(!node->tag_actions) {
288b5663de9SDag-Erling Smørgrav 			log_err("out of memory");
289b5663de9SDag-Erling Smørgrav 			return 0;
290b5663de9SDag-Erling Smørgrav 		}
291b5663de9SDag-Erling Smørgrav 		node->tag_actions_size = (size_t)cfg->num_tags;
292b5663de9SDag-Erling Smørgrav 	}
293b5663de9SDag-Erling Smørgrav 	/* parse tag */
294b5663de9SDag-Erling Smørgrav 	if((tagid=find_tag_id(cfg, tag)) == -1) {
295b5663de9SDag-Erling Smørgrav 		log_err("cannot parse tag (define-tag it): %s %s", str, tag);
296b5663de9SDag-Erling Smørgrav 		return 0;
297b5663de9SDag-Erling Smørgrav 	}
298b5663de9SDag-Erling Smørgrav 	if((size_t)tagid >= node->tag_actions_size) {
299b5663de9SDag-Erling Smørgrav 		log_err("tagid too large for array %s %s", str, tag);
300b5663de9SDag-Erling Smørgrav 		return 0;
301b5663de9SDag-Erling Smørgrav 	}
302b5663de9SDag-Erling Smørgrav 	if(!local_zone_str2type(action, &t)) {
303b5663de9SDag-Erling Smørgrav 		log_err("cannot parse access control action type: %s %s %s",
304b5663de9SDag-Erling Smørgrav 			str, tag, action);
305b5663de9SDag-Erling Smørgrav 		return 0;
306b5663de9SDag-Erling Smørgrav 	}
307b5663de9SDag-Erling Smørgrav 	node->tag_actions[tagid] = (uint8_t)t;
308b5663de9SDag-Erling Smørgrav 	return 1;
309b5663de9SDag-Erling Smørgrav }
310b5663de9SDag-Erling Smørgrav 
311b5663de9SDag-Erling Smørgrav /** check wire data parse */
312b5663de9SDag-Erling Smørgrav static int
313bc892140SDag-Erling Smørgrav check_data(const char* data, const struct config_strlist* head)
314b5663de9SDag-Erling Smørgrav {
315b5663de9SDag-Erling Smørgrav 	char buf[65536];
316b5663de9SDag-Erling Smørgrav 	uint8_t rr[LDNS_RR_BUF_SIZE];
317b5663de9SDag-Erling Smørgrav 	size_t len = sizeof(rr);
318b5663de9SDag-Erling Smørgrav 	int res;
319bc892140SDag-Erling Smørgrav 	/* '.' is sufficient for validation, and it makes the call to
320bc892140SDag-Erling Smørgrav 	 * sldns_wirerr_get_type() simpler below. */
321bc892140SDag-Erling Smørgrav 	snprintf(buf, sizeof(buf), "%s %s", ".", data);
322b5663de9SDag-Erling Smørgrav 	res = sldns_str2wire_rr_buf(buf, rr, &len, NULL, 3600, NULL, 0,
323b5663de9SDag-Erling Smørgrav 		NULL, 0);
324bc892140SDag-Erling Smørgrav 
325bc892140SDag-Erling Smørgrav 	/* Reject it if we would end up having CNAME and other data (including
326bc892140SDag-Erling Smørgrav 	 * another CNAME) for the same tag. */
327bc892140SDag-Erling Smørgrav 	if(res == 0 && head) {
328bc892140SDag-Erling Smørgrav 		const char* err_data = NULL;
329bc892140SDag-Erling Smørgrav 
330bc892140SDag-Erling Smørgrav 		if(sldns_wirerr_get_type(rr, len, 1) == LDNS_RR_TYPE_CNAME) {
331bc892140SDag-Erling Smørgrav 			/* adding CNAME while other data already exists. */
332bc892140SDag-Erling Smørgrav 			err_data = data;
333bc892140SDag-Erling Smørgrav 		} else {
334bc892140SDag-Erling Smørgrav 			snprintf(buf, sizeof(buf), "%s %s", ".", head->str);
335bc892140SDag-Erling Smørgrav 			len = sizeof(rr);
336bc892140SDag-Erling Smørgrav 			res = sldns_str2wire_rr_buf(buf, rr, &len, NULL, 3600,
337bc892140SDag-Erling Smørgrav 				NULL, 0, NULL, 0);
338bc892140SDag-Erling Smørgrav 			if(res != 0) {
339bc892140SDag-Erling Smørgrav 				/* This should be impossible here as head->str
340bc892140SDag-Erling Smørgrav 				 * has been validated, but we check it just in
341bc892140SDag-Erling Smørgrav 				 * case. */
342bc892140SDag-Erling Smørgrav 				return 0;
343bc892140SDag-Erling Smørgrav 			}
344bc892140SDag-Erling Smørgrav 			if(sldns_wirerr_get_type(rr, len, 1) ==
345bc892140SDag-Erling Smørgrav 				LDNS_RR_TYPE_CNAME) /* already have CNAME */
346bc892140SDag-Erling Smørgrav 				err_data = head->str;
347bc892140SDag-Erling Smørgrav 		}
348bc892140SDag-Erling Smørgrav 		if(err_data) {
349bc892140SDag-Erling Smørgrav 			log_err("redirect tag data '%s' must not coexist with "
350bc892140SDag-Erling Smørgrav 				"other data.", err_data);
351bc892140SDag-Erling Smørgrav 			return 0;
352bc892140SDag-Erling Smørgrav 		}
353bc892140SDag-Erling Smørgrav 	}
354b5663de9SDag-Erling Smørgrav 	if(res == 0)
355b5663de9SDag-Erling Smørgrav 		return 1;
356b5663de9SDag-Erling Smørgrav 	log_err("rr data [char %d] parse error %s",
35725039b37SCy Schubert 		(int)LDNS_WIREPARSE_OFFSET(res)-2,
358b5663de9SDag-Erling Smørgrav 		sldns_get_errorstr_parse(res));
359b5663de9SDag-Erling Smørgrav 	return 0;
360b5663de9SDag-Erling Smørgrav }
361b5663de9SDag-Erling Smørgrav 
362b5663de9SDag-Erling Smørgrav /** apply acl_tag_data string */
363b5663de9SDag-Erling Smørgrav static int
364b5663de9SDag-Erling Smørgrav acl_list_tag_data_cfg(struct acl_list* acl, struct config_file* cfg,
365865f46b2SCy Schubert 	const char* str, const char* tag, const char* data,
366865f46b2SCy Schubert 	int is_interface, int port)
367b5663de9SDag-Erling Smørgrav {
368b5663de9SDag-Erling Smørgrav 	struct acl_addr* node;
369b5663de9SDag-Erling Smørgrav 	int tagid;
370b5663de9SDag-Erling Smørgrav 	char* dupdata;
371865f46b2SCy Schubert 	if(!(node=acl_find_or_create_str2addr(acl, str, is_interface, port))) {
372865f46b2SCy Schubert 		if(is_interface)
373865f46b2SCy Schubert 			log_err("non-configured interface: %s", str);
374b5663de9SDag-Erling Smørgrav 		return 0;
375865f46b2SCy Schubert 	}
376b5663de9SDag-Erling Smørgrav 	/* allocate array if not yet */
377b5663de9SDag-Erling Smørgrav 	if(!node->tag_datas) {
378b5663de9SDag-Erling Smørgrav 		node->tag_datas = (struct config_strlist**)regional_alloc_zero(
379b5663de9SDag-Erling Smørgrav 			acl->region, sizeof(*node->tag_datas)*cfg->num_tags);
380b5663de9SDag-Erling Smørgrav 		if(!node->tag_datas) {
381b5663de9SDag-Erling Smørgrav 			log_err("out of memory");
382b5663de9SDag-Erling Smørgrav 			return 0;
383b5663de9SDag-Erling Smørgrav 		}
384b5663de9SDag-Erling Smørgrav 		node->tag_datas_size = (size_t)cfg->num_tags;
385b5663de9SDag-Erling Smørgrav 	}
386b5663de9SDag-Erling Smørgrav 	/* parse tag */
387b5663de9SDag-Erling Smørgrav 	if((tagid=find_tag_id(cfg, tag)) == -1) {
388b5663de9SDag-Erling Smørgrav 		log_err("cannot parse tag (define-tag it): %s %s", str, tag);
389b5663de9SDag-Erling Smørgrav 		return 0;
390b5663de9SDag-Erling Smørgrav 	}
391b5663de9SDag-Erling Smørgrav 	if((size_t)tagid >= node->tag_datas_size) {
392b5663de9SDag-Erling Smørgrav 		log_err("tagid too large for array %s %s", str, tag);
393b5663de9SDag-Erling Smørgrav 		return 0;
394b5663de9SDag-Erling Smørgrav 	}
395b5663de9SDag-Erling Smørgrav 
396b5663de9SDag-Erling Smørgrav 	/* check data? */
397bc892140SDag-Erling Smørgrav 	if(!check_data(data, node->tag_datas[tagid])) {
398b5663de9SDag-Erling Smørgrav 		log_err("cannot parse access-control-tag data: %s %s '%s'",
399b5663de9SDag-Erling Smørgrav 			str, tag, data);
400b5663de9SDag-Erling Smørgrav 		return 0;
401b5663de9SDag-Erling Smørgrav 	}
402b5663de9SDag-Erling Smørgrav 
403b5663de9SDag-Erling Smørgrav 	dupdata = regional_strdup(acl->region, data);
404b5663de9SDag-Erling Smørgrav 	if(!dupdata) {
405b5663de9SDag-Erling Smørgrav 		log_err("out of memory");
406b5663de9SDag-Erling Smørgrav 		return 0;
407b5663de9SDag-Erling Smørgrav 	}
408b5663de9SDag-Erling Smørgrav 	if(!cfg_region_strlist_insert(acl->region,
409b5663de9SDag-Erling Smørgrav 		&(node->tag_datas[tagid]), dupdata)) {
410b5663de9SDag-Erling Smørgrav 		log_err("out of memory");
411b5663de9SDag-Erling Smørgrav 		return 0;
412b5663de9SDag-Erling Smørgrav 	}
413b5663de9SDag-Erling Smørgrav 	return 1;
414b5663de9SDag-Erling Smørgrav }
415b5663de9SDag-Erling Smørgrav 
416b7579f77SDag-Erling Smørgrav /** read acl_list config */
417b7579f77SDag-Erling Smørgrav static int
418865f46b2SCy Schubert read_acl_list(struct acl_list* acl, struct config_str2list* acls)
419b7579f77SDag-Erling Smørgrav {
420b7579f77SDag-Erling Smørgrav 	struct config_str2list* p;
421865f46b2SCy Schubert 	for(p = acls; p; p = p->next) {
422b7579f77SDag-Erling Smørgrav 		log_assert(p->str && p->str2);
423b7579f77SDag-Erling Smørgrav 		if(!acl_list_str_cfg(acl, p->str, p->str2, 1))
424b7579f77SDag-Erling Smørgrav 			return 0;
425b7579f77SDag-Erling Smørgrav 	}
426b7579f77SDag-Erling Smørgrav 	return 1;
427b7579f77SDag-Erling Smørgrav }
428b7579f77SDag-Erling Smørgrav 
429865f46b2SCy Schubert /** read acl view config */
430b5663de9SDag-Erling Smørgrav static int
431865f46b2SCy Schubert read_acl_view(struct acl_list* acl, struct config_str2list** acl_view,
432865f46b2SCy Schubert 	struct views* v)
433b5663de9SDag-Erling Smørgrav {
434865f46b2SCy Schubert 	struct config_str2list* np, *p = *acl_view;
435865f46b2SCy Schubert 	*acl_view = NULL;
436b5663de9SDag-Erling Smørgrav 	while(p) {
437b5663de9SDag-Erling Smørgrav 		log_assert(p->str && p->str2);
438865f46b2SCy Schubert 		if(!acl_list_view_cfg(acl, p->str, p->str2, v, 0, 0)) {
439865f46b2SCy Schubert 			config_deldblstrlist(p);
440b5663de9SDag-Erling Smørgrav 			return 0;
441b5663de9SDag-Erling Smørgrav 		}
442b5663de9SDag-Erling Smørgrav 		/* free the items as we go to free up memory */
443b5663de9SDag-Erling Smørgrav 		np = p->next;
444b5663de9SDag-Erling Smørgrav 		free(p->str);
445b5663de9SDag-Erling Smørgrav 		free(p->str2);
446b5663de9SDag-Erling Smørgrav 		free(p);
447b5663de9SDag-Erling Smørgrav 		p = np;
448b5663de9SDag-Erling Smørgrav 	}
449b5663de9SDag-Erling Smørgrav 	return 1;
450b5663de9SDag-Erling Smørgrav }
451b5663de9SDag-Erling Smørgrav 
452865f46b2SCy Schubert /** read acl tags config */
453bc892140SDag-Erling Smørgrav static int
454865f46b2SCy Schubert read_acl_tags(struct acl_list* acl, struct config_strbytelist** acl_tags)
455bc892140SDag-Erling Smørgrav {
456865f46b2SCy Schubert 	struct config_strbytelist* np, *p = *acl_tags;
457865f46b2SCy Schubert 	*acl_tags = NULL;
458bc892140SDag-Erling Smørgrav 	while(p) {
459bc892140SDag-Erling Smørgrav 		log_assert(p->str && p->str2);
460865f46b2SCy Schubert 		if(!acl_list_tags_cfg(acl, p->str, p->str2, p->str2len, 0, 0)) {
461865f46b2SCy Schubert 			config_del_strbytelist(p);
462bc892140SDag-Erling Smørgrav 			return 0;
463bc892140SDag-Erling Smørgrav 		}
464bc892140SDag-Erling Smørgrav 		/* free the items as we go to free up memory */
465bc892140SDag-Erling Smørgrav 		np = p->next;
466bc892140SDag-Erling Smørgrav 		free(p->str);
467bc892140SDag-Erling Smørgrav 		free(p->str2);
468bc892140SDag-Erling Smørgrav 		free(p);
469bc892140SDag-Erling Smørgrav 		p = np;
470bc892140SDag-Erling Smørgrav 	}
471bc892140SDag-Erling Smørgrav 	return 1;
472bc892140SDag-Erling Smørgrav }
473bc892140SDag-Erling Smørgrav 
474b5663de9SDag-Erling Smørgrav /** read acl tag actions config */
475b5663de9SDag-Erling Smørgrav static int
476865f46b2SCy Schubert read_acl_tag_actions(struct acl_list* acl, struct config_file* cfg,
477865f46b2SCy Schubert 	struct config_str3list** acl_tag_actions)
478b5663de9SDag-Erling Smørgrav {
479b5663de9SDag-Erling Smørgrav 	struct config_str3list* p, *np;
480865f46b2SCy Schubert 	p = *acl_tag_actions;
481865f46b2SCy Schubert 	*acl_tag_actions = NULL;
482b5663de9SDag-Erling Smørgrav 	while(p) {
483b5663de9SDag-Erling Smørgrav 		log_assert(p->str && p->str2 && p->str3);
484b5663de9SDag-Erling Smørgrav 		if(!acl_list_tag_action_cfg(acl, cfg, p->str, p->str2,
485865f46b2SCy Schubert 			p->str3, 0, 0)) {
486b5663de9SDag-Erling Smørgrav 			config_deltrplstrlist(p);
487b5663de9SDag-Erling Smørgrav 			return 0;
488b5663de9SDag-Erling Smørgrav 		}
489b5663de9SDag-Erling Smørgrav 		/* free the items as we go to free up memory */
490b5663de9SDag-Erling Smørgrav 		np = p->next;
491b5663de9SDag-Erling Smørgrav 		free(p->str);
492b5663de9SDag-Erling Smørgrav 		free(p->str2);
493b5663de9SDag-Erling Smørgrav 		free(p->str3);
494b5663de9SDag-Erling Smørgrav 		free(p);
495b5663de9SDag-Erling Smørgrav 		p = np;
496b5663de9SDag-Erling Smørgrav 	}
497b5663de9SDag-Erling Smørgrav 	return 1;
498b5663de9SDag-Erling Smørgrav }
499b5663de9SDag-Erling Smørgrav 
500b5663de9SDag-Erling Smørgrav /** read acl tag datas config */
501b5663de9SDag-Erling Smørgrav static int
502865f46b2SCy Schubert read_acl_tag_datas(struct acl_list* acl, struct config_file* cfg,
503865f46b2SCy Schubert 	struct config_str3list** acl_tag_datas)
504b5663de9SDag-Erling Smørgrav {
505b5663de9SDag-Erling Smørgrav 	struct config_str3list* p, *np;
506865f46b2SCy Schubert 	p = *acl_tag_datas;
507865f46b2SCy Schubert 	*acl_tag_datas = NULL;
508b5663de9SDag-Erling Smørgrav 	while(p) {
509b5663de9SDag-Erling Smørgrav 		log_assert(p->str && p->str2 && p->str3);
510865f46b2SCy Schubert 		if(!acl_list_tag_data_cfg(acl, cfg, p->str, p->str2, p->str3,
511865f46b2SCy Schubert 			0, 0)) {
512b5663de9SDag-Erling Smørgrav 			config_deltrplstrlist(p);
513b5663de9SDag-Erling Smørgrav 			return 0;
514b5663de9SDag-Erling Smørgrav 		}
515b5663de9SDag-Erling Smørgrav 		/* free the items as we go to free up memory */
516b5663de9SDag-Erling Smørgrav 		np = p->next;
517b5663de9SDag-Erling Smørgrav 		free(p->str);
518b5663de9SDag-Erling Smørgrav 		free(p->str2);
519b5663de9SDag-Erling Smørgrav 		free(p->str3);
520b5663de9SDag-Erling Smørgrav 		free(p);
521b5663de9SDag-Erling Smørgrav 		p = np;
522b5663de9SDag-Erling Smørgrav 	}
523b5663de9SDag-Erling Smørgrav 	return 1;
524b5663de9SDag-Erling Smørgrav }
525b5663de9SDag-Erling Smørgrav 
526b7579f77SDag-Erling Smørgrav int
527bc892140SDag-Erling Smørgrav acl_list_apply_cfg(struct acl_list* acl, struct config_file* cfg,
528bc892140SDag-Erling Smørgrav 	struct views* v)
529b7579f77SDag-Erling Smørgrav {
530b7579f77SDag-Erling Smørgrav 	regional_free_all(acl->region);
531b7579f77SDag-Erling Smørgrav 	addr_tree_init(&acl->tree);
532865f46b2SCy Schubert 	if(!read_acl_list(acl, cfg->acls))
533b7579f77SDag-Erling Smørgrav 		return 0;
534865f46b2SCy Schubert 	if(!read_acl_view(acl, &cfg->acl_view, v))
535bc892140SDag-Erling Smørgrav 		return 0;
536865f46b2SCy Schubert 	if(!read_acl_tags(acl, &cfg->acl_tags))
537b5663de9SDag-Erling Smørgrav 		return 0;
538865f46b2SCy Schubert 	if(!read_acl_tag_actions(acl, cfg, &cfg->acl_tag_actions))
539b5663de9SDag-Erling Smørgrav 		return 0;
540865f46b2SCy Schubert 	if(!read_acl_tag_datas(acl, cfg, &cfg->acl_tag_datas))
541b5663de9SDag-Erling Smørgrav 		return 0;
542b7579f77SDag-Erling Smørgrav 	/* insert defaults, with '0' to ignore them if they are duplicates */
543865f46b2SCy Schubert 	/* the 'refuse' defaults for /0 are now done per interface instead */
544b7579f77SDag-Erling Smørgrav 	if(!acl_list_str_cfg(acl, "127.0.0.0/8", "allow", 0))
545b7579f77SDag-Erling Smørgrav 		return 0;
546b7579f77SDag-Erling Smørgrav 	if(cfg->do_ip6) {
547b7579f77SDag-Erling Smørgrav 		if(!acl_list_str_cfg(acl, "::1", "allow", 0))
548b7579f77SDag-Erling Smørgrav 			return 0;
549b7579f77SDag-Erling Smørgrav 		if(!acl_list_str_cfg(acl, "::ffff:127.0.0.1", "allow", 0))
550b7579f77SDag-Erling Smørgrav 			return 0;
551b7579f77SDag-Erling Smørgrav 	}
552b7579f77SDag-Erling Smørgrav 	addr_tree_init_parents(&acl->tree);
553b7579f77SDag-Erling Smørgrav 	return 1;
554b7579f77SDag-Erling Smørgrav }
555b7579f77SDag-Erling Smørgrav 
556865f46b2SCy Schubert void
557865f46b2SCy Schubert acl_interface_init(struct acl_list* acl_interface)
558865f46b2SCy Schubert {
559865f46b2SCy Schubert 	regional_free_all(acl_interface->region);
560865f46b2SCy Schubert 	/* We want comparison in the tree to include only address and port.
561865f46b2SCy Schubert 	 * We don't care about comparing node->net. All addresses in the
562865f46b2SCy Schubert 	 * acl_interface->tree should have either 32 (ipv4) or 128 (ipv6).
563865f46b2SCy Schubert 	 * Initialise with the appropriate compare function but keep treating
564865f46b2SCy Schubert 	 * it as an addr_tree. */
565865f46b2SCy Schubert 	addr_tree_addrport_init(&acl_interface->tree);
566865f46b2SCy Schubert }
567865f46b2SCy Schubert 
568865f46b2SCy Schubert static int
569865f46b2SCy Schubert read_acl_interface_action(struct acl_list* acl_interface,
570865f46b2SCy Schubert 	struct config_str2list* acls, int port)
571865f46b2SCy Schubert {
572865f46b2SCy Schubert 	struct config_str2list* p;
573865f46b2SCy Schubert 	for(p = acls; p; p = p->next) {
574865f46b2SCy Schubert 		char** resif = NULL;
575865f46b2SCy Schubert 		int num_resif = 0;
576865f46b2SCy Schubert 		int i;
577865f46b2SCy Schubert 		log_assert(p->str && p->str2);
578865f46b2SCy Schubert 		if(!resolve_interface_names(&p->str, 1, NULL, &resif, &num_resif))
579865f46b2SCy Schubert 			return 0;
580865f46b2SCy Schubert 		for(i = 0; i<num_resif; i++) {
581865f46b2SCy Schubert 			if(!acl_interface_str_cfg(acl_interface, resif[i], p->str2, port)){
582865f46b2SCy Schubert 				config_del_strarray(resif, num_resif);
583865f46b2SCy Schubert 				return 0;
584865f46b2SCy Schubert 			}
585865f46b2SCy Schubert 		}
586865f46b2SCy Schubert 		config_del_strarray(resif, num_resif);
587865f46b2SCy Schubert 	}
588865f46b2SCy Schubert 	return 1;
589865f46b2SCy Schubert }
590865f46b2SCy Schubert 
591865f46b2SCy Schubert /** read acl view config for interface */
592865f46b2SCy Schubert static int
593865f46b2SCy Schubert read_acl_interface_view(struct acl_list* acl_interface,
594865f46b2SCy Schubert 	struct config_str2list** acl_view,
595865f46b2SCy Schubert 	struct views* v, int port)
596865f46b2SCy Schubert {
597865f46b2SCy Schubert 	struct config_str2list* np, *p = *acl_view;
598865f46b2SCy Schubert 	*acl_view = NULL;
599865f46b2SCy Schubert 	while(p) {
600865f46b2SCy Schubert 		char** resif = NULL;
601865f46b2SCy Schubert 		int num_resif = 0;
602865f46b2SCy Schubert 		int i;
603865f46b2SCy Schubert 		log_assert(p->str && p->str2);
604865f46b2SCy Schubert 		if(!resolve_interface_names(&p->str, 1, NULL, &resif, &num_resif)) {
605865f46b2SCy Schubert 			config_deldblstrlist(p);
606865f46b2SCy Schubert 			return 0;
607865f46b2SCy Schubert 		}
608865f46b2SCy Schubert 		for(i = 0; i<num_resif; i++) {
609865f46b2SCy Schubert 			if(!acl_list_view_cfg(acl_interface, resif[i], p->str2,
610865f46b2SCy Schubert 				v, 1, port)) {
611865f46b2SCy Schubert 				config_del_strarray(resif, num_resif);
612865f46b2SCy Schubert 				config_deldblstrlist(p);
613865f46b2SCy Schubert 				return 0;
614865f46b2SCy Schubert 			}
615865f46b2SCy Schubert 		}
616865f46b2SCy Schubert 		config_del_strarray(resif, num_resif);
617865f46b2SCy Schubert 		/* free the items as we go to free up memory */
618865f46b2SCy Schubert 		np = p->next;
619865f46b2SCy Schubert 		free(p->str);
620865f46b2SCy Schubert 		free(p->str2);
621865f46b2SCy Schubert 		free(p);
622865f46b2SCy Schubert 		p = np;
623865f46b2SCy Schubert 	}
624865f46b2SCy Schubert 	return 1;
625865f46b2SCy Schubert }
626865f46b2SCy Schubert 
627865f46b2SCy Schubert /** read acl tags config for interface */
628865f46b2SCy Schubert static int
629865f46b2SCy Schubert read_acl_interface_tags(struct acl_list* acl_interface,
630865f46b2SCy Schubert 	struct config_strbytelist** acl_tags, int port)
631865f46b2SCy Schubert {
632865f46b2SCy Schubert 	struct config_strbytelist* np, *p = *acl_tags;
633865f46b2SCy Schubert 	*acl_tags = NULL;
634865f46b2SCy Schubert 	while(p) {
635865f46b2SCy Schubert 		char** resif = NULL;
636865f46b2SCy Schubert 		int num_resif = 0;
637865f46b2SCy Schubert 		int i;
638865f46b2SCy Schubert 		log_assert(p->str && p->str2);
639865f46b2SCy Schubert 		if(!resolve_interface_names(&p->str, 1, NULL, &resif, &num_resif)) {
640865f46b2SCy Schubert 			config_del_strbytelist(p);
641865f46b2SCy Schubert 			return 0;
642865f46b2SCy Schubert 		}
643865f46b2SCy Schubert 		for(i = 0; i<num_resif; i++) {
644865f46b2SCy Schubert 			if(!acl_list_tags_cfg(acl_interface, resif[i], p->str2,
645865f46b2SCy Schubert 				p->str2len, 1, port)) {
646865f46b2SCy Schubert 				config_del_strbytelist(p);
647865f46b2SCy Schubert 				config_del_strarray(resif, num_resif);
648865f46b2SCy Schubert 				return 0;
649865f46b2SCy Schubert 			}
650865f46b2SCy Schubert 		}
651865f46b2SCy Schubert 		config_del_strarray(resif, num_resif);
652865f46b2SCy Schubert 		/* free the items as we go to free up memory */
653865f46b2SCy Schubert 		np = p->next;
654865f46b2SCy Schubert 		free(p->str);
655865f46b2SCy Schubert 		free(p->str2);
656865f46b2SCy Schubert 		free(p);
657865f46b2SCy Schubert 		p = np;
658865f46b2SCy Schubert 	}
659865f46b2SCy Schubert 	return 1;
660865f46b2SCy Schubert }
661865f46b2SCy Schubert 
662865f46b2SCy Schubert /** read acl tag actions config for interface*/
663865f46b2SCy Schubert static int
664865f46b2SCy Schubert read_acl_interface_tag_actions(struct acl_list* acl_interface,
665865f46b2SCy Schubert 	struct config_file* cfg,
666865f46b2SCy Schubert 	struct config_str3list** acl_tag_actions, int port)
667865f46b2SCy Schubert {
668865f46b2SCy Schubert 	struct config_str3list* p, *np;
669865f46b2SCy Schubert 	p = *acl_tag_actions;
670865f46b2SCy Schubert 	*acl_tag_actions = NULL;
671865f46b2SCy Schubert 	while(p) {
672865f46b2SCy Schubert 		char** resif = NULL;
673865f46b2SCy Schubert 		int num_resif = 0;
674865f46b2SCy Schubert 		int i;
675865f46b2SCy Schubert 		log_assert(p->str && p->str2 && p->str3);
676865f46b2SCy Schubert 		if(!resolve_interface_names(&p->str, 1, NULL, &resif, &num_resif)) {
677865f46b2SCy Schubert 			config_deltrplstrlist(p);
678865f46b2SCy Schubert 			return 0;
679865f46b2SCy Schubert 		}
680865f46b2SCy Schubert 		for(i = 0; i<num_resif; i++) {
681865f46b2SCy Schubert 			if(!acl_list_tag_action_cfg(acl_interface, cfg,
682865f46b2SCy Schubert 				resif[i], p->str2, p->str3, 1, port)) {
683865f46b2SCy Schubert 				config_deltrplstrlist(p);
684865f46b2SCy Schubert 				config_del_strarray(resif, num_resif);
685865f46b2SCy Schubert 				return 0;
686865f46b2SCy Schubert 			}
687865f46b2SCy Schubert 		}
688865f46b2SCy Schubert 		config_del_strarray(resif, num_resif);
689865f46b2SCy Schubert 		/* free the items as we go to free up memory */
690865f46b2SCy Schubert 		np = p->next;
691865f46b2SCy Schubert 		free(p->str);
692865f46b2SCy Schubert 		free(p->str2);
693865f46b2SCy Schubert 		free(p->str3);
694865f46b2SCy Schubert 		free(p);
695865f46b2SCy Schubert 		p = np;
696865f46b2SCy Schubert 	}
697865f46b2SCy Schubert 	return 1;
698865f46b2SCy Schubert }
699865f46b2SCy Schubert 
700865f46b2SCy Schubert /** read acl tag datas config for interface */
701865f46b2SCy Schubert static int
702865f46b2SCy Schubert read_acl_interface_tag_datas(struct acl_list* acl_interface,
703865f46b2SCy Schubert 	struct config_file* cfg,
704865f46b2SCy Schubert 	struct config_str3list** acl_tag_datas, int port)
705865f46b2SCy Schubert {
706865f46b2SCy Schubert 	struct config_str3list* p, *np;
707865f46b2SCy Schubert 	p = *acl_tag_datas;
708865f46b2SCy Schubert 	*acl_tag_datas = NULL;
709865f46b2SCy Schubert 	while(p) {
710865f46b2SCy Schubert 		char** resif = NULL;
711865f46b2SCy Schubert 		int num_resif = 0;
712865f46b2SCy Schubert 		int i;
713865f46b2SCy Schubert 		log_assert(p->str && p->str2 && p->str3);
714865f46b2SCy Schubert 		if(!resolve_interface_names(&p->str, 1, NULL, &resif, &num_resif)) {
715865f46b2SCy Schubert 			config_deltrplstrlist(p);
716865f46b2SCy Schubert 			return 0;
717865f46b2SCy Schubert 		}
718865f46b2SCy Schubert 		for(i = 0; i<num_resif; i++) {
719865f46b2SCy Schubert 			if(!acl_list_tag_data_cfg(acl_interface, cfg,
720865f46b2SCy Schubert 				resif[i], p->str2, p->str3, 1, port)) {
721865f46b2SCy Schubert 				config_deltrplstrlist(p);
722865f46b2SCy Schubert 				config_del_strarray(resif, num_resif);
723865f46b2SCy Schubert 				return 0;
724865f46b2SCy Schubert 			}
725865f46b2SCy Schubert 		}
726865f46b2SCy Schubert 		config_del_strarray(resif, num_resif);
727865f46b2SCy Schubert 		/* free the items as we go to free up memory */
728865f46b2SCy Schubert 		np = p->next;
729865f46b2SCy Schubert 		free(p->str);
730865f46b2SCy Schubert 		free(p->str2);
731865f46b2SCy Schubert 		free(p->str3);
732865f46b2SCy Schubert 		free(p);
733865f46b2SCy Schubert 		p = np;
734865f46b2SCy Schubert 	}
735865f46b2SCy Schubert 	return 1;
736865f46b2SCy Schubert }
737865f46b2SCy Schubert 
738865f46b2SCy Schubert int
739865f46b2SCy Schubert acl_interface_apply_cfg(struct acl_list* acl_interface, struct config_file* cfg,
740865f46b2SCy Schubert 	struct views* v)
741865f46b2SCy Schubert {
742865f46b2SCy Schubert 	if(!read_acl_interface_action(acl_interface, cfg->interface_actions,
743865f46b2SCy Schubert 		cfg->port))
744865f46b2SCy Schubert 		return 0;
745865f46b2SCy Schubert 	if(!read_acl_interface_view(acl_interface, &cfg->interface_view, v,
746865f46b2SCy Schubert 		cfg->port))
747865f46b2SCy Schubert 		return 0;
748865f46b2SCy Schubert 	if(!read_acl_interface_tags(acl_interface, &cfg->interface_tags,
749865f46b2SCy Schubert 		cfg->port))
750865f46b2SCy Schubert 		return 0;
751865f46b2SCy Schubert 	if(!read_acl_interface_tag_actions(acl_interface, cfg,
752865f46b2SCy Schubert 		&cfg->interface_tag_actions, cfg->port))
753865f46b2SCy Schubert 		return 0;
754865f46b2SCy Schubert 	if(!read_acl_interface_tag_datas(acl_interface, cfg,
755865f46b2SCy Schubert 		&cfg->interface_tag_datas, cfg->port))
756865f46b2SCy Schubert 		return 0;
757865f46b2SCy Schubert 	addr_tree_init_parents(&acl_interface->tree);
758865f46b2SCy Schubert 	return 1;
759865f46b2SCy Schubert }
760865f46b2SCy Schubert 
761b7579f77SDag-Erling Smørgrav enum acl_access
762b5663de9SDag-Erling Smørgrav acl_get_control(struct acl_addr* acl)
763b5663de9SDag-Erling Smørgrav {
764b5663de9SDag-Erling Smørgrav 	if(acl) return acl->control;
765b5663de9SDag-Erling Smørgrav 	return acl_deny;
766b5663de9SDag-Erling Smørgrav }
767b5663de9SDag-Erling Smørgrav 
768b5663de9SDag-Erling Smørgrav struct acl_addr*
769b5663de9SDag-Erling Smørgrav acl_addr_lookup(struct acl_list* acl, struct sockaddr_storage* addr,
770b7579f77SDag-Erling Smørgrav         socklen_t addrlen)
771b7579f77SDag-Erling Smørgrav {
772b5663de9SDag-Erling Smørgrav 	return (struct acl_addr*)addr_tree_lookup(&acl->tree,
773b7579f77SDag-Erling Smørgrav 		addr, addrlen);
774b7579f77SDag-Erling Smørgrav }
775b7579f77SDag-Erling Smørgrav 
776b7579f77SDag-Erling Smørgrav size_t
777b7579f77SDag-Erling Smørgrav acl_list_get_mem(struct acl_list* acl)
778b7579f77SDag-Erling Smørgrav {
779b7579f77SDag-Erling Smørgrav 	if(!acl) return 0;
780b7579f77SDag-Erling Smørgrav 	return sizeof(*acl) + regional_get_mem(acl->region);
781b7579f77SDag-Erling Smørgrav }
782a39a5a69SCy Schubert 
783a39a5a69SCy Schubert const char* acl_access_to_str(enum acl_access acl)
784a39a5a69SCy Schubert {
785a39a5a69SCy Schubert 	switch(acl) {
786a39a5a69SCy Schubert 	case acl_deny: return "deny";
787a39a5a69SCy Schubert 	case acl_refuse: return "refuse";
788a39a5a69SCy Schubert 	case acl_deny_non_local: return "deny_non_local";
789a39a5a69SCy Schubert 	case acl_refuse_non_local: return "refuse_non_local";
790a39a5a69SCy Schubert 	case acl_allow: return "allow";
791a39a5a69SCy Schubert 	case acl_allow_snoop: return "allow_snoop";
792a39a5a69SCy Schubert 	case acl_allow_setrd: return "allow_setrd";
793a39a5a69SCy Schubert 	default: break;
794a39a5a69SCy Schubert 	}
795a39a5a69SCy Schubert 	return "unknown";
796a39a5a69SCy Schubert }
797a39a5a69SCy Schubert 
798a39a5a69SCy Schubert void
799a39a5a69SCy Schubert log_acl_action(const char* action, struct sockaddr_storage* addr,
800a39a5a69SCy Schubert 	socklen_t addrlen, enum acl_access acl, struct acl_addr* acladdr)
801a39a5a69SCy Schubert {
802a39a5a69SCy Schubert 	char a[128], n[128];
803a39a5a69SCy Schubert 	uint16_t port;
804a39a5a69SCy Schubert 	addr_to_str(addr, addrlen, a, sizeof(a));
805a39a5a69SCy Schubert 	port = ntohs(((struct sockaddr_in*)addr)->sin_port);
806a39a5a69SCy Schubert 	if(acladdr) {
807a39a5a69SCy Schubert 		addr_to_str(&acladdr->node.addr, acladdr->node.addrlen,
808a39a5a69SCy Schubert 			n, sizeof(n));
809a39a5a69SCy Schubert 		verbose(VERB_ALGO, "%s query from %s port %d because of "
810*be771a7bSCy Schubert 			"%s/%d %s%s", action, a, (int)port, n,
811*be771a7bSCy Schubert 			acladdr->node.net,
812*be771a7bSCy Schubert 			acladdr->is_interface?"(ACL on interface IP) ":"",
813a39a5a69SCy Schubert 			acl_access_to_str(acl));
814a39a5a69SCy Schubert 	} else {
815a39a5a69SCy Schubert 		verbose(VERB_ALGO, "%s query from %s port %d", action, a,
816a39a5a69SCy Schubert 			(int)port);
817a39a5a69SCy Schubert 	}
818a39a5a69SCy Schubert }
819*be771a7bSCy Schubert 
820*be771a7bSCy Schubert void acl_list_swap_tree(struct acl_list* acl, struct acl_list* data)
821*be771a7bSCy Schubert {
822*be771a7bSCy Schubert 	/* swap tree and region */
823*be771a7bSCy Schubert 	rbtree_type oldtree = acl->tree;
824*be771a7bSCy Schubert 	struct regional* oldregion = acl->region;
825*be771a7bSCy Schubert 	acl->tree = data->tree;
826*be771a7bSCy Schubert 	acl->region = data->region;
827*be771a7bSCy Schubert 	data->tree = oldtree;
828*be771a7bSCy Schubert 	data->region = oldregion;
829*be771a7bSCy Schubert }
830