xref: /freebsd/contrib/unbound/daemon/acl_list.c (revision be771a7b7f4580a30d99e41a5bb1b93a385a119d)
1 /*
2  * daemon/acl_list.h - client access control storage for the server.
3  *
4  * Copyright (c) 2007, NLnet Labs. All rights reserved.
5  *
6  * This software is open source.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * Redistributions of source code must retain the above copyright notice,
13  * this list of conditions and the following disclaimer.
14  *
15  * Redistributions in binary form must reproduce the above copyright notice,
16  * this list of conditions and the following disclaimer in the documentation
17  * and/or other materials provided with the distribution.
18  *
19  * Neither the name of the NLNET LABS nor the names of its contributors may
20  * be used to endorse or promote products derived from this software without
21  * specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27  * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
29  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34  */
35 
36 /**
37  * \file
38  *
39  * This file helps the server keep out queries from outside sources, that
40  * should not be answered.
41  */
42 #include "config.h"
43 #include "daemon/acl_list.h"
44 #include "util/regional.h"
45 #include "util/log.h"
46 #include "util/config_file.h"
47 #include "util/net_help.h"
48 #include "services/localzone.h"
49 #include "services/listen_dnsport.h"
50 #include "sldns/str2wire.h"
51 
52 struct acl_list*
53 acl_list_create(void)
54 {
55 	struct acl_list* acl = (struct acl_list*)calloc(1,
56 		sizeof(struct acl_list));
57 	if(!acl)
58 		return NULL;
59 	acl->region = regional_create();
60 	if(!acl->region) {
61 		acl_list_delete(acl);
62 		return NULL;
63 	}
64 	return acl;
65 }
66 
67 void
68 acl_list_delete(struct acl_list* acl)
69 {
70 	if(!acl)
71 		return;
72 	regional_destroy(acl->region);
73 	free(acl);
74 }
75 
76 /** insert new address into acl_list structure */
77 static struct acl_addr*
78 acl_list_insert(struct acl_list* acl, struct sockaddr_storage* addr,
79 	socklen_t addrlen, int net, enum acl_access control,
80 	int complain_duplicates)
81 {
82 	struct acl_addr* node = regional_alloc_zero(acl->region,
83 		sizeof(struct acl_addr));
84 	if(!node)
85 		return NULL;
86 	node->control = control;
87 	if(!addr_tree_insert(&acl->tree, &node->node, addr, addrlen, net)) {
88 		if(complain_duplicates)
89 			verbose(VERB_QUERY, "duplicate acl address ignored.");
90 	}
91 	return node;
92 }
93 
94 /** parse str to acl_access enum */
95 static int
96 parse_acl_access(const char* str, enum acl_access* control)
97 {
98 	if(strcmp(str, "allow") == 0)
99 		*control = acl_allow;
100 	else if(strcmp(str, "deny") == 0)
101 		*control = acl_deny;
102 	else if(strcmp(str, "refuse") == 0)
103 		*control = acl_refuse;
104 	else if(strcmp(str, "deny_non_local") == 0)
105 		*control = acl_deny_non_local;
106 	else if(strcmp(str, "refuse_non_local") == 0)
107 		*control = acl_refuse_non_local;
108 	else if(strcmp(str, "allow_snoop") == 0)
109 		*control = acl_allow_snoop;
110 	else if(strcmp(str, "allow_setrd") == 0)
111 		*control = acl_allow_setrd;
112 	else if (strcmp(str, "allow_cookie") == 0)
113 		*control = acl_allow_cookie;
114 	else {
115 		log_err("access control type %s unknown", str);
116 		return 0;
117 	}
118 	return 1;
119 }
120 
121 /** apply acl_list string */
122 static int
123 acl_list_str_cfg(struct acl_list* acl, const char* str, const char* s2,
124 	int complain_duplicates)
125 {
126 	struct sockaddr_storage addr;
127 	int net;
128 	socklen_t addrlen;
129 	enum acl_access control;
130 	if(!parse_acl_access(s2, &control)) {
131 		return 0;
132 	}
133 	if(!netblockstrtoaddr(str, UNBOUND_DNS_PORT, &addr, &addrlen, &net)) {
134 		log_err("cannot parse access control: %s %s", str, s2);
135 		return 0;
136 	}
137 	if(!acl_list_insert(acl, &addr, addrlen, net, control,
138 		complain_duplicates)) {
139 		log_err("out of memory");
140 		return 0;
141 	}
142 	return 1;
143 }
144 
145 /** find or create node (NULL on parse or error) */
146 static struct acl_addr*
147 acl_find_or_create_str2addr(struct acl_list* acl, const char* str,
148 	int is_interface, int port)
149 {
150 	struct acl_addr* node;
151 	struct sockaddr_storage addr;
152 	socklen_t addrlen;
153 	int net = (str_is_ip6(str)?128:32);
154 	if(is_interface) {
155 		if(!extstrtoaddr(str, &addr, &addrlen, port)) {
156 			log_err("cannot parse interface: %s", str);
157 			return NULL;
158 		}
159 	} else {
160 		if(!netblockstrtoaddr(str, UNBOUND_DNS_PORT, &addr, &addrlen, &net)) {
161 			log_err("cannot parse netblock: %s", str);
162 			return NULL;
163 		}
164 	}
165 	/* find or create node */
166 	if(!(node=(struct acl_addr*)addr_tree_find(&acl->tree, &addr,
167 		addrlen, net)) && !is_interface) {
168 		/* create node, type 'allow' since otherwise tags are
169 		 * pointless, can override with specific access-control: cfg */
170 		if(!(node=(struct acl_addr*)acl_list_insert(acl, &addr,
171 			addrlen, net, acl_allow, 1))) {
172 			log_err("out of memory");
173 			return NULL;
174 		}
175 	}
176 	return node;
177 }
178 
179 /** find or create node (NULL on error) */
180 static struct acl_addr*
181 acl_find_or_create(struct acl_list* acl, struct sockaddr_storage* addr,
182 	socklen_t addrlen, enum acl_access control)
183 {
184 	struct acl_addr* node;
185 	int net = (addr_is_ip6(addr, addrlen)?128:32);
186 	/* find or create node */
187 	if(!(node=(struct acl_addr*)addr_tree_find(&acl->tree, addr,
188 		addrlen, net))) {
189 		/* create node;
190 		 * can override with specific access-control: cfg */
191 		if(!(node=(struct acl_addr*)acl_list_insert(acl, addr,
192 			addrlen, net, control, 1))) {
193 			log_err("out of memory");
194 			return NULL;
195 		}
196 	}
197 	return node;
198 }
199 
200 /** apply acl_interface string */
201 static int
202 acl_interface_str_cfg(struct acl_list* acl_interface, const char* iface,
203 	const char* s2, int port)
204 {
205 	struct acl_addr* node;
206 	enum acl_access control;
207 	if(!parse_acl_access(s2, &control)) {
208 		return 0;
209 	}
210 	if(!(node=acl_find_or_create_str2addr(acl_interface, iface, 1, port))) {
211 		log_err("cannot update ACL on non-configured interface: %s %d",
212 			iface, port);
213 		return 0;
214 	}
215 	node->control = control;
216 	return 1;
217 }
218 
219 struct acl_addr*
220 acl_interface_insert(struct acl_list* acl_interface,
221 	struct sockaddr_storage* addr, socklen_t addrlen,
222 	enum acl_access control)
223 {
224 	struct acl_addr* node = acl_find_or_create(acl_interface, addr, addrlen, control);
225 	node->is_interface = 1;
226 	return node;
227 }
228 
229 /** apply acl_tag string */
230 static int
231 acl_list_tags_cfg(struct acl_list* acl, const char* str, uint8_t* bitmap,
232 	size_t bitmaplen, int is_interface, int port)
233 {
234 	struct acl_addr* node;
235 	if(!(node=acl_find_or_create_str2addr(acl, str, is_interface, port))) {
236 		if(is_interface)
237 			log_err("non-configured interface: %s", str);
238 		return 0;
239 	}
240 	node->taglen = bitmaplen;
241 	node->taglist = regional_alloc_init(acl->region, bitmap, bitmaplen);
242 	if(!node->taglist) {
243 		log_err("out of memory");
244 		return 0;
245 	}
246 	return 1;
247 }
248 
249 /** apply acl_view string */
250 static int
251 acl_list_view_cfg(struct acl_list* acl, const char* str, const char* str2,
252 	struct views* vs, int is_interface, int port)
253 {
254 	struct acl_addr* node;
255 	if(!(node=acl_find_or_create_str2addr(acl, str, is_interface, port))) {
256 		if(is_interface)
257 			log_err("non-configured interface: %s", str);
258 		return 0;
259 	}
260 	node->view = views_find_view(vs, str2, 0 /* get read lock*/);
261 	if(!node->view) {
262 		log_err("no view with name: %s", str2);
263 		return 0;
264 	}
265 	lock_rw_unlock(&node->view->lock);
266 	return 1;
267 }
268 
269 /** apply acl_tag_action string */
270 static int
271 acl_list_tag_action_cfg(struct acl_list* acl, struct config_file* cfg,
272 	const char* str, const char* tag, const char* action,
273 	int is_interface, int port)
274 {
275 	struct acl_addr* node;
276 	int tagid;
277 	enum localzone_type t;
278 	if(!(node=acl_find_or_create_str2addr(acl, str, is_interface, port))) {
279 		if(is_interface)
280 			log_err("non-configured interface: %s", str);
281 		return 0;
282 	}
283 	/* allocate array if not yet */
284 	if(!node->tag_actions) {
285 		node->tag_actions = (uint8_t*)regional_alloc_zero(acl->region,
286 			sizeof(*node->tag_actions)*cfg->num_tags);
287 		if(!node->tag_actions) {
288 			log_err("out of memory");
289 			return 0;
290 		}
291 		node->tag_actions_size = (size_t)cfg->num_tags;
292 	}
293 	/* parse tag */
294 	if((tagid=find_tag_id(cfg, tag)) == -1) {
295 		log_err("cannot parse tag (define-tag it): %s %s", str, tag);
296 		return 0;
297 	}
298 	if((size_t)tagid >= node->tag_actions_size) {
299 		log_err("tagid too large for array %s %s", str, tag);
300 		return 0;
301 	}
302 	if(!local_zone_str2type(action, &t)) {
303 		log_err("cannot parse access control action type: %s %s %s",
304 			str, tag, action);
305 		return 0;
306 	}
307 	node->tag_actions[tagid] = (uint8_t)t;
308 	return 1;
309 }
310 
311 /** check wire data parse */
312 static int
313 check_data(const char* data, const struct config_strlist* head)
314 {
315 	char buf[65536];
316 	uint8_t rr[LDNS_RR_BUF_SIZE];
317 	size_t len = sizeof(rr);
318 	int res;
319 	/* '.' is sufficient for validation, and it makes the call to
320 	 * sldns_wirerr_get_type() simpler below. */
321 	snprintf(buf, sizeof(buf), "%s %s", ".", data);
322 	res = sldns_str2wire_rr_buf(buf, rr, &len, NULL, 3600, NULL, 0,
323 		NULL, 0);
324 
325 	/* Reject it if we would end up having CNAME and other data (including
326 	 * another CNAME) for the same tag. */
327 	if(res == 0 && head) {
328 		const char* err_data = NULL;
329 
330 		if(sldns_wirerr_get_type(rr, len, 1) == LDNS_RR_TYPE_CNAME) {
331 			/* adding CNAME while other data already exists. */
332 			err_data = data;
333 		} else {
334 			snprintf(buf, sizeof(buf), "%s %s", ".", head->str);
335 			len = sizeof(rr);
336 			res = sldns_str2wire_rr_buf(buf, rr, &len, NULL, 3600,
337 				NULL, 0, NULL, 0);
338 			if(res != 0) {
339 				/* This should be impossible here as head->str
340 				 * has been validated, but we check it just in
341 				 * case. */
342 				return 0;
343 			}
344 			if(sldns_wirerr_get_type(rr, len, 1) ==
345 				LDNS_RR_TYPE_CNAME) /* already have CNAME */
346 				err_data = head->str;
347 		}
348 		if(err_data) {
349 			log_err("redirect tag data '%s' must not coexist with "
350 				"other data.", err_data);
351 			return 0;
352 		}
353 	}
354 	if(res == 0)
355 		return 1;
356 	log_err("rr data [char %d] parse error %s",
357 		(int)LDNS_WIREPARSE_OFFSET(res)-2,
358 		sldns_get_errorstr_parse(res));
359 	return 0;
360 }
361 
362 /** apply acl_tag_data string */
363 static int
364 acl_list_tag_data_cfg(struct acl_list* acl, struct config_file* cfg,
365 	const char* str, const char* tag, const char* data,
366 	int is_interface, int port)
367 {
368 	struct acl_addr* node;
369 	int tagid;
370 	char* dupdata;
371 	if(!(node=acl_find_or_create_str2addr(acl, str, is_interface, port))) {
372 		if(is_interface)
373 			log_err("non-configured interface: %s", str);
374 		return 0;
375 	}
376 	/* allocate array if not yet */
377 	if(!node->tag_datas) {
378 		node->tag_datas = (struct config_strlist**)regional_alloc_zero(
379 			acl->region, sizeof(*node->tag_datas)*cfg->num_tags);
380 		if(!node->tag_datas) {
381 			log_err("out of memory");
382 			return 0;
383 		}
384 		node->tag_datas_size = (size_t)cfg->num_tags;
385 	}
386 	/* parse tag */
387 	if((tagid=find_tag_id(cfg, tag)) == -1) {
388 		log_err("cannot parse tag (define-tag it): %s %s", str, tag);
389 		return 0;
390 	}
391 	if((size_t)tagid >= node->tag_datas_size) {
392 		log_err("tagid too large for array %s %s", str, tag);
393 		return 0;
394 	}
395 
396 	/* check data? */
397 	if(!check_data(data, node->tag_datas[tagid])) {
398 		log_err("cannot parse access-control-tag data: %s %s '%s'",
399 			str, tag, data);
400 		return 0;
401 	}
402 
403 	dupdata = regional_strdup(acl->region, data);
404 	if(!dupdata) {
405 		log_err("out of memory");
406 		return 0;
407 	}
408 	if(!cfg_region_strlist_insert(acl->region,
409 		&(node->tag_datas[tagid]), dupdata)) {
410 		log_err("out of memory");
411 		return 0;
412 	}
413 	return 1;
414 }
415 
416 /** read acl_list config */
417 static int
418 read_acl_list(struct acl_list* acl, struct config_str2list* acls)
419 {
420 	struct config_str2list* p;
421 	for(p = acls; p; p = p->next) {
422 		log_assert(p->str && p->str2);
423 		if(!acl_list_str_cfg(acl, p->str, p->str2, 1))
424 			return 0;
425 	}
426 	return 1;
427 }
428 
429 /** read acl view config */
430 static int
431 read_acl_view(struct acl_list* acl, struct config_str2list** acl_view,
432 	struct views* v)
433 {
434 	struct config_str2list* np, *p = *acl_view;
435 	*acl_view = NULL;
436 	while(p) {
437 		log_assert(p->str && p->str2);
438 		if(!acl_list_view_cfg(acl, p->str, p->str2, v, 0, 0)) {
439 			config_deldblstrlist(p);
440 			return 0;
441 		}
442 		/* free the items as we go to free up memory */
443 		np = p->next;
444 		free(p->str);
445 		free(p->str2);
446 		free(p);
447 		p = np;
448 	}
449 	return 1;
450 }
451 
452 /** read acl tags config */
453 static int
454 read_acl_tags(struct acl_list* acl, struct config_strbytelist** acl_tags)
455 {
456 	struct config_strbytelist* np, *p = *acl_tags;
457 	*acl_tags = NULL;
458 	while(p) {
459 		log_assert(p->str && p->str2);
460 		if(!acl_list_tags_cfg(acl, p->str, p->str2, p->str2len, 0, 0)) {
461 			config_del_strbytelist(p);
462 			return 0;
463 		}
464 		/* free the items as we go to free up memory */
465 		np = p->next;
466 		free(p->str);
467 		free(p->str2);
468 		free(p);
469 		p = np;
470 	}
471 	return 1;
472 }
473 
474 /** read acl tag actions config */
475 static int
476 read_acl_tag_actions(struct acl_list* acl, struct config_file* cfg,
477 	struct config_str3list** acl_tag_actions)
478 {
479 	struct config_str3list* p, *np;
480 	p = *acl_tag_actions;
481 	*acl_tag_actions = NULL;
482 	while(p) {
483 		log_assert(p->str && p->str2 && p->str3);
484 		if(!acl_list_tag_action_cfg(acl, cfg, p->str, p->str2,
485 			p->str3, 0, 0)) {
486 			config_deltrplstrlist(p);
487 			return 0;
488 		}
489 		/* free the items as we go to free up memory */
490 		np = p->next;
491 		free(p->str);
492 		free(p->str2);
493 		free(p->str3);
494 		free(p);
495 		p = np;
496 	}
497 	return 1;
498 }
499 
500 /** read acl tag datas config */
501 static int
502 read_acl_tag_datas(struct acl_list* acl, struct config_file* cfg,
503 	struct config_str3list** acl_tag_datas)
504 {
505 	struct config_str3list* p, *np;
506 	p = *acl_tag_datas;
507 	*acl_tag_datas = NULL;
508 	while(p) {
509 		log_assert(p->str && p->str2 && p->str3);
510 		if(!acl_list_tag_data_cfg(acl, cfg, p->str, p->str2, p->str3,
511 			0, 0)) {
512 			config_deltrplstrlist(p);
513 			return 0;
514 		}
515 		/* free the items as we go to free up memory */
516 		np = p->next;
517 		free(p->str);
518 		free(p->str2);
519 		free(p->str3);
520 		free(p);
521 		p = np;
522 	}
523 	return 1;
524 }
525 
526 int
527 acl_list_apply_cfg(struct acl_list* acl, struct config_file* cfg,
528 	struct views* v)
529 {
530 	regional_free_all(acl->region);
531 	addr_tree_init(&acl->tree);
532 	if(!read_acl_list(acl, cfg->acls))
533 		return 0;
534 	if(!read_acl_view(acl, &cfg->acl_view, v))
535 		return 0;
536 	if(!read_acl_tags(acl, &cfg->acl_tags))
537 		return 0;
538 	if(!read_acl_tag_actions(acl, cfg, &cfg->acl_tag_actions))
539 		return 0;
540 	if(!read_acl_tag_datas(acl, cfg, &cfg->acl_tag_datas))
541 		return 0;
542 	/* insert defaults, with '0' to ignore them if they are duplicates */
543 	/* the 'refuse' defaults for /0 are now done per interface instead */
544 	if(!acl_list_str_cfg(acl, "127.0.0.0/8", "allow", 0))
545 		return 0;
546 	if(cfg->do_ip6) {
547 		if(!acl_list_str_cfg(acl, "::1", "allow", 0))
548 			return 0;
549 		if(!acl_list_str_cfg(acl, "::ffff:127.0.0.1", "allow", 0))
550 			return 0;
551 	}
552 	addr_tree_init_parents(&acl->tree);
553 	return 1;
554 }
555 
556 void
557 acl_interface_init(struct acl_list* acl_interface)
558 {
559 	regional_free_all(acl_interface->region);
560 	/* We want comparison in the tree to include only address and port.
561 	 * We don't care about comparing node->net. All addresses in the
562 	 * acl_interface->tree should have either 32 (ipv4) or 128 (ipv6).
563 	 * Initialise with the appropriate compare function but keep treating
564 	 * it as an addr_tree. */
565 	addr_tree_addrport_init(&acl_interface->tree);
566 }
567 
568 static int
569 read_acl_interface_action(struct acl_list* acl_interface,
570 	struct config_str2list* acls, int port)
571 {
572 	struct config_str2list* p;
573 	for(p = acls; p; p = p->next) {
574 		char** resif = NULL;
575 		int num_resif = 0;
576 		int i;
577 		log_assert(p->str && p->str2);
578 		if(!resolve_interface_names(&p->str, 1, NULL, &resif, &num_resif))
579 			return 0;
580 		for(i = 0; i<num_resif; i++) {
581 			if(!acl_interface_str_cfg(acl_interface, resif[i], p->str2, port)){
582 				config_del_strarray(resif, num_resif);
583 				return 0;
584 			}
585 		}
586 		config_del_strarray(resif, num_resif);
587 	}
588 	return 1;
589 }
590 
591 /** read acl view config for interface */
592 static int
593 read_acl_interface_view(struct acl_list* acl_interface,
594 	struct config_str2list** acl_view,
595 	struct views* v, int port)
596 {
597 	struct config_str2list* np, *p = *acl_view;
598 	*acl_view = NULL;
599 	while(p) {
600 		char** resif = NULL;
601 		int num_resif = 0;
602 		int i;
603 		log_assert(p->str && p->str2);
604 		if(!resolve_interface_names(&p->str, 1, NULL, &resif, &num_resif)) {
605 			config_deldblstrlist(p);
606 			return 0;
607 		}
608 		for(i = 0; i<num_resif; i++) {
609 			if(!acl_list_view_cfg(acl_interface, resif[i], p->str2,
610 				v, 1, port)) {
611 				config_del_strarray(resif, num_resif);
612 				config_deldblstrlist(p);
613 				return 0;
614 			}
615 		}
616 		config_del_strarray(resif, num_resif);
617 		/* free the items as we go to free up memory */
618 		np = p->next;
619 		free(p->str);
620 		free(p->str2);
621 		free(p);
622 		p = np;
623 	}
624 	return 1;
625 }
626 
627 /** read acl tags config for interface */
628 static int
629 read_acl_interface_tags(struct acl_list* acl_interface,
630 	struct config_strbytelist** acl_tags, int port)
631 {
632 	struct config_strbytelist* np, *p = *acl_tags;
633 	*acl_tags = NULL;
634 	while(p) {
635 		char** resif = NULL;
636 		int num_resif = 0;
637 		int i;
638 		log_assert(p->str && p->str2);
639 		if(!resolve_interface_names(&p->str, 1, NULL, &resif, &num_resif)) {
640 			config_del_strbytelist(p);
641 			return 0;
642 		}
643 		for(i = 0; i<num_resif; i++) {
644 			if(!acl_list_tags_cfg(acl_interface, resif[i], p->str2,
645 				p->str2len, 1, port)) {
646 				config_del_strbytelist(p);
647 				config_del_strarray(resif, num_resif);
648 				return 0;
649 			}
650 		}
651 		config_del_strarray(resif, num_resif);
652 		/* free the items as we go to free up memory */
653 		np = p->next;
654 		free(p->str);
655 		free(p->str2);
656 		free(p);
657 		p = np;
658 	}
659 	return 1;
660 }
661 
662 /** read acl tag actions config for interface*/
663 static int
664 read_acl_interface_tag_actions(struct acl_list* acl_interface,
665 	struct config_file* cfg,
666 	struct config_str3list** acl_tag_actions, int port)
667 {
668 	struct config_str3list* p, *np;
669 	p = *acl_tag_actions;
670 	*acl_tag_actions = NULL;
671 	while(p) {
672 		char** resif = NULL;
673 		int num_resif = 0;
674 		int i;
675 		log_assert(p->str && p->str2 && p->str3);
676 		if(!resolve_interface_names(&p->str, 1, NULL, &resif, &num_resif)) {
677 			config_deltrplstrlist(p);
678 			return 0;
679 		}
680 		for(i = 0; i<num_resif; i++) {
681 			if(!acl_list_tag_action_cfg(acl_interface, cfg,
682 				resif[i], p->str2, p->str3, 1, port)) {
683 				config_deltrplstrlist(p);
684 				config_del_strarray(resif, num_resif);
685 				return 0;
686 			}
687 		}
688 		config_del_strarray(resif, num_resif);
689 		/* free the items as we go to free up memory */
690 		np = p->next;
691 		free(p->str);
692 		free(p->str2);
693 		free(p->str3);
694 		free(p);
695 		p = np;
696 	}
697 	return 1;
698 }
699 
700 /** read acl tag datas config for interface */
701 static int
702 read_acl_interface_tag_datas(struct acl_list* acl_interface,
703 	struct config_file* cfg,
704 	struct config_str3list** acl_tag_datas, int port)
705 {
706 	struct config_str3list* p, *np;
707 	p = *acl_tag_datas;
708 	*acl_tag_datas = NULL;
709 	while(p) {
710 		char** resif = NULL;
711 		int num_resif = 0;
712 		int i;
713 		log_assert(p->str && p->str2 && p->str3);
714 		if(!resolve_interface_names(&p->str, 1, NULL, &resif, &num_resif)) {
715 			config_deltrplstrlist(p);
716 			return 0;
717 		}
718 		for(i = 0; i<num_resif; i++) {
719 			if(!acl_list_tag_data_cfg(acl_interface, cfg,
720 				resif[i], p->str2, p->str3, 1, port)) {
721 				config_deltrplstrlist(p);
722 				config_del_strarray(resif, num_resif);
723 				return 0;
724 			}
725 		}
726 		config_del_strarray(resif, num_resif);
727 		/* free the items as we go to free up memory */
728 		np = p->next;
729 		free(p->str);
730 		free(p->str2);
731 		free(p->str3);
732 		free(p);
733 		p = np;
734 	}
735 	return 1;
736 }
737 
738 int
739 acl_interface_apply_cfg(struct acl_list* acl_interface, struct config_file* cfg,
740 	struct views* v)
741 {
742 	if(!read_acl_interface_action(acl_interface, cfg->interface_actions,
743 		cfg->port))
744 		return 0;
745 	if(!read_acl_interface_view(acl_interface, &cfg->interface_view, v,
746 		cfg->port))
747 		return 0;
748 	if(!read_acl_interface_tags(acl_interface, &cfg->interface_tags,
749 		cfg->port))
750 		return 0;
751 	if(!read_acl_interface_tag_actions(acl_interface, cfg,
752 		&cfg->interface_tag_actions, cfg->port))
753 		return 0;
754 	if(!read_acl_interface_tag_datas(acl_interface, cfg,
755 		&cfg->interface_tag_datas, cfg->port))
756 		return 0;
757 	addr_tree_init_parents(&acl_interface->tree);
758 	return 1;
759 }
760 
761 enum acl_access
762 acl_get_control(struct acl_addr* acl)
763 {
764 	if(acl) return acl->control;
765 	return acl_deny;
766 }
767 
768 struct acl_addr*
769 acl_addr_lookup(struct acl_list* acl, struct sockaddr_storage* addr,
770         socklen_t addrlen)
771 {
772 	return (struct acl_addr*)addr_tree_lookup(&acl->tree,
773 		addr, addrlen);
774 }
775 
776 size_t
777 acl_list_get_mem(struct acl_list* acl)
778 {
779 	if(!acl) return 0;
780 	return sizeof(*acl) + regional_get_mem(acl->region);
781 }
782 
783 const char* acl_access_to_str(enum acl_access acl)
784 {
785 	switch(acl) {
786 	case acl_deny: return "deny";
787 	case acl_refuse: return "refuse";
788 	case acl_deny_non_local: return "deny_non_local";
789 	case acl_refuse_non_local: return "refuse_non_local";
790 	case acl_allow: return "allow";
791 	case acl_allow_snoop: return "allow_snoop";
792 	case acl_allow_setrd: return "allow_setrd";
793 	default: break;
794 	}
795 	return "unknown";
796 }
797 
798 void
799 log_acl_action(const char* action, struct sockaddr_storage* addr,
800 	socklen_t addrlen, enum acl_access acl, struct acl_addr* acladdr)
801 {
802 	char a[128], n[128];
803 	uint16_t port;
804 	addr_to_str(addr, addrlen, a, sizeof(a));
805 	port = ntohs(((struct sockaddr_in*)addr)->sin_port);
806 	if(acladdr) {
807 		addr_to_str(&acladdr->node.addr, acladdr->node.addrlen,
808 			n, sizeof(n));
809 		verbose(VERB_ALGO, "%s query from %s port %d because of "
810 			"%s/%d %s%s", action, a, (int)port, n,
811 			acladdr->node.net,
812 			acladdr->is_interface?"(ACL on interface IP) ":"",
813 			acl_access_to_str(acl));
814 	} else {
815 		verbose(VERB_ALGO, "%s query from %s port %d", action, a,
816 			(int)port);
817 	}
818 }
819 
820 void acl_list_swap_tree(struct acl_list* acl, struct acl_list* data)
821 {
822 	/* swap tree and region */
823 	rbtree_type oldtree = acl->tree;
824 	struct regional* oldregion = acl->region;
825 	acl->tree = data->tree;
826 	acl->region = data->region;
827 	data->tree = oldtree;
828 	data->region = oldregion;
829 }
830