xref: /openbsd-src/usr.sbin/unbound/daemon/acl_list.c (revision 8b7325af55f9372784d083aa385d31c4cebf9890)
1933707f3Ssthen /*
2933707f3Ssthen  * daemon/acl_list.h - client access control storage for the server.
3933707f3Ssthen  *
4933707f3Ssthen  * Copyright (c) 2007, NLnet Labs. All rights reserved.
5933707f3Ssthen  *
6933707f3Ssthen  * This software is open source.
7933707f3Ssthen  *
8933707f3Ssthen  * Redistribution and use in source and binary forms, with or without
9933707f3Ssthen  * modification, are permitted provided that the following conditions
10933707f3Ssthen  * are met:
11933707f3Ssthen  *
12933707f3Ssthen  * Redistributions of source code must retain the above copyright notice,
13933707f3Ssthen  * this list of conditions and the following disclaimer.
14933707f3Ssthen  *
15933707f3Ssthen  * Redistributions in binary form must reproduce the above copyright notice,
16933707f3Ssthen  * this list of conditions and the following disclaimer in the documentation
17933707f3Ssthen  * and/or other materials provided with the distribution.
18933707f3Ssthen  *
19933707f3Ssthen  * Neither the name of the NLNET LABS nor the names of its contributors may
20933707f3Ssthen  * be used to endorse or promote products derived from this software without
21933707f3Ssthen  * specific prior written permission.
22933707f3Ssthen  *
23933707f3Ssthen  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
245d76a658Ssthen  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
255d76a658Ssthen  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
265d76a658Ssthen  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
275d76a658Ssthen  * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
285d76a658Ssthen  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
295d76a658Ssthen  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
305d76a658Ssthen  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
315d76a658Ssthen  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
325d76a658Ssthen  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
335d76a658Ssthen  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34933707f3Ssthen  */
35933707f3Ssthen 
36933707f3Ssthen /**
37933707f3Ssthen  * \file
38933707f3Ssthen  *
39933707f3Ssthen  * This file helps the server keep out queries from outside sources, that
40933707f3Ssthen  * should not be answered.
41933707f3Ssthen  */
42933707f3Ssthen #include "config.h"
43933707f3Ssthen #include "daemon/acl_list.h"
44933707f3Ssthen #include "util/regional.h"
45933707f3Ssthen #include "util/log.h"
46933707f3Ssthen #include "util/config_file.h"
47933707f3Ssthen #include "util/net_help.h"
4877079be7Ssthen #include "services/localzone.h"
4945872187Ssthen #include "services/listen_dnsport.h"
5077079be7Ssthen #include "sldns/str2wire.h"
51933707f3Ssthen 
52933707f3Ssthen struct acl_list*
acl_list_create(void)53933707f3Ssthen acl_list_create(void)
54933707f3Ssthen {
55933707f3Ssthen 	struct acl_list* acl = (struct acl_list*)calloc(1,
56933707f3Ssthen 		sizeof(struct acl_list));
57933707f3Ssthen 	if(!acl)
58933707f3Ssthen 		return NULL;
59933707f3Ssthen 	acl->region = regional_create();
60933707f3Ssthen 	if(!acl->region) {
61933707f3Ssthen 		acl_list_delete(acl);
62933707f3Ssthen 		return NULL;
63933707f3Ssthen 	}
64933707f3Ssthen 	return acl;
65933707f3Ssthen }
66933707f3Ssthen 
67933707f3Ssthen void
acl_list_delete(struct acl_list * acl)68933707f3Ssthen acl_list_delete(struct acl_list* acl)
69933707f3Ssthen {
70933707f3Ssthen 	if(!acl)
71933707f3Ssthen 		return;
72933707f3Ssthen 	regional_destroy(acl->region);
73933707f3Ssthen 	free(acl);
74933707f3Ssthen }
75933707f3Ssthen 
76933707f3Ssthen /** insert new address into acl_list structure */
7777079be7Ssthen static struct acl_addr*
acl_list_insert(struct acl_list * acl,struct sockaddr_storage * addr,socklen_t addrlen,int net,enum acl_access control,int complain_duplicates)78933707f3Ssthen acl_list_insert(struct acl_list* acl, struct sockaddr_storage* addr,
79933707f3Ssthen 	socklen_t addrlen, int net, enum acl_access control,
80933707f3Ssthen 	int complain_duplicates)
81933707f3Ssthen {
8277079be7Ssthen 	struct acl_addr* node = regional_alloc_zero(acl->region,
83933707f3Ssthen 		sizeof(struct acl_addr));
84933707f3Ssthen 	if(!node)
8577079be7Ssthen 		return NULL;
86933707f3Ssthen 	node->control = control;
87933707f3Ssthen 	if(!addr_tree_insert(&acl->tree, &node->node, addr, addrlen, net)) {
88933707f3Ssthen 		if(complain_duplicates)
89933707f3Ssthen 			verbose(VERB_QUERY, "duplicate acl address ignored.");
90933707f3Ssthen 	}
9177079be7Ssthen 	return node;
92933707f3Ssthen }
93933707f3Ssthen 
9445872187Ssthen /** parse str to acl_access enum */
9545872187Ssthen static int
parse_acl_access(const char * str,enum acl_access * control)9645872187Ssthen parse_acl_access(const char* str, enum acl_access* control)
9745872187Ssthen {
9845872187Ssthen 	if(strcmp(str, "allow") == 0)
9945872187Ssthen 		*control = acl_allow;
10045872187Ssthen 	else if(strcmp(str, "deny") == 0)
10145872187Ssthen 		*control = acl_deny;
10245872187Ssthen 	else if(strcmp(str, "refuse") == 0)
10345872187Ssthen 		*control = acl_refuse;
10445872187Ssthen 	else if(strcmp(str, "deny_non_local") == 0)
10545872187Ssthen 		*control = acl_deny_non_local;
10645872187Ssthen 	else if(strcmp(str, "refuse_non_local") == 0)
10745872187Ssthen 		*control = acl_refuse_non_local;
10845872187Ssthen 	else if(strcmp(str, "allow_snoop") == 0)
10945872187Ssthen 		*control = acl_allow_snoop;
11045872187Ssthen 	else if(strcmp(str, "allow_setrd") == 0)
11145872187Ssthen 		*control = acl_allow_setrd;
112*8b7325afSsthen 	else if (strcmp(str, "allow_cookie") == 0)
113*8b7325afSsthen 		*control = acl_allow_cookie;
11445872187Ssthen 	else {
11545872187Ssthen 		log_err("access control type %s unknown", str);
11645872187Ssthen 		return 0;
11745872187Ssthen 	}
11845872187Ssthen 	return 1;
11945872187Ssthen }
12045872187Ssthen 
121933707f3Ssthen /** apply acl_list string */
122933707f3Ssthen static int
acl_list_str_cfg(struct acl_list * acl,const char * str,const char * s2,int complain_duplicates)123933707f3Ssthen acl_list_str_cfg(struct acl_list* acl, const char* str, const char* s2,
124933707f3Ssthen 	int complain_duplicates)
125933707f3Ssthen {
126933707f3Ssthen 	struct sockaddr_storage addr;
127933707f3Ssthen 	int net;
128933707f3Ssthen 	socklen_t addrlen;
129933707f3Ssthen 	enum acl_access control;
13045872187Ssthen 	if(!parse_acl_access(s2, &control)) {
131933707f3Ssthen 		return 0;
132933707f3Ssthen 	}
133933707f3Ssthen 	if(!netblockstrtoaddr(str, UNBOUND_DNS_PORT, &addr, &addrlen, &net)) {
134933707f3Ssthen 		log_err("cannot parse access control: %s %s", str, s2);
135933707f3Ssthen 		return 0;
136933707f3Ssthen 	}
137933707f3Ssthen 	if(!acl_list_insert(acl, &addr, addrlen, net, control,
138933707f3Ssthen 		complain_duplicates)) {
139933707f3Ssthen 		log_err("out of memory");
140933707f3Ssthen 		return 0;
141933707f3Ssthen 	}
142933707f3Ssthen 	return 1;
143933707f3Ssthen }
144933707f3Ssthen 
14577079be7Ssthen /** find or create node (NULL on parse or error) */
14677079be7Ssthen static struct acl_addr*
acl_find_or_create_str2addr(struct acl_list * acl,const char * str,int is_interface,int port)14745872187Ssthen acl_find_or_create_str2addr(struct acl_list* acl, const char* str,
14845872187Ssthen 	int is_interface, int port)
14977079be7Ssthen {
15077079be7Ssthen 	struct acl_addr* node;
15177079be7Ssthen 	struct sockaddr_storage addr;
15277079be7Ssthen 	socklen_t addrlen;
15345872187Ssthen 	int net = (str_is_ip6(str)?128:32);
15445872187Ssthen 	if(is_interface) {
15545872187Ssthen 		if(!extstrtoaddr(str, &addr, &addrlen, port)) {
15645872187Ssthen 			log_err("cannot parse interface: %s", str);
15745872187Ssthen 			return NULL;
15845872187Ssthen 		}
15945872187Ssthen 	} else {
16077079be7Ssthen 		if(!netblockstrtoaddr(str, UNBOUND_DNS_PORT, &addr, &addrlen, &net)) {
16177079be7Ssthen 			log_err("cannot parse netblock: %s", str);
16277079be7Ssthen 			return NULL;
16377079be7Ssthen 		}
16445872187Ssthen 	}
16577079be7Ssthen 	/* find or create node */
16677079be7Ssthen 	if(!(node=(struct acl_addr*)addr_tree_find(&acl->tree, &addr,
16745872187Ssthen 		addrlen, net)) && !is_interface) {
16877079be7Ssthen 		/* create node, type 'allow' since otherwise tags are
16977079be7Ssthen 		 * pointless, can override with specific access-control: cfg */
17077079be7Ssthen 		if(!(node=(struct acl_addr*)acl_list_insert(acl, &addr,
17177079be7Ssthen 			addrlen, net, acl_allow, 1))) {
17277079be7Ssthen 			log_err("out of memory");
17377079be7Ssthen 			return NULL;
17477079be7Ssthen 		}
17577079be7Ssthen 	}
17677079be7Ssthen 	return node;
17777079be7Ssthen }
17877079be7Ssthen 
17945872187Ssthen /** find or create node (NULL on error) */
18045872187Ssthen static struct acl_addr*
acl_find_or_create(struct acl_list * acl,struct sockaddr_storage * addr,socklen_t addrlen,enum acl_access control)18145872187Ssthen acl_find_or_create(struct acl_list* acl, struct sockaddr_storage* addr,
18245872187Ssthen 	socklen_t addrlen, enum acl_access control)
18345872187Ssthen {
18445872187Ssthen 	struct acl_addr* node;
18545872187Ssthen 	int net = (addr_is_ip6(addr, addrlen)?128:32);
18645872187Ssthen 	/* find or create node */
18745872187Ssthen 	if(!(node=(struct acl_addr*)addr_tree_find(&acl->tree, addr,
18845872187Ssthen 		addrlen, net))) {
18945872187Ssthen 		/* create node;
19045872187Ssthen 		 * can override with specific access-control: cfg */
19145872187Ssthen 		if(!(node=(struct acl_addr*)acl_list_insert(acl, addr,
19245872187Ssthen 			addrlen, net, control, 1))) {
19345872187Ssthen 			log_err("out of memory");
19445872187Ssthen 			return NULL;
19545872187Ssthen 		}
19645872187Ssthen 	}
19745872187Ssthen 	return node;
19845872187Ssthen }
19945872187Ssthen 
20045872187Ssthen /** apply acl_interface string */
20145872187Ssthen static int
acl_interface_str_cfg(struct acl_list * acl_interface,const char * iface,const char * s2,int port)20245872187Ssthen acl_interface_str_cfg(struct acl_list* acl_interface, const char* iface,
20345872187Ssthen 	const char* s2, int port)
20445872187Ssthen {
20545872187Ssthen 	struct acl_addr* node;
20645872187Ssthen 	enum acl_access control;
20745872187Ssthen 	if(!parse_acl_access(s2, &control)) {
20845872187Ssthen 		return 0;
20945872187Ssthen 	}
21045872187Ssthen 	if(!(node=acl_find_or_create_str2addr(acl_interface, iface, 1, port))) {
21145872187Ssthen 		log_err("cannot update ACL on non-configured interface: %s %d",
21245872187Ssthen 			iface, port);
21345872187Ssthen 		return 0;
21445872187Ssthen 	}
21545872187Ssthen 	node->control = control;
21645872187Ssthen 	return 1;
21745872187Ssthen }
21845872187Ssthen 
21945872187Ssthen struct acl_addr*
acl_interface_insert(struct acl_list * acl_interface,struct sockaddr_storage * addr,socklen_t addrlen,enum acl_access control)22045872187Ssthen acl_interface_insert(struct acl_list* acl_interface,
22145872187Ssthen 	struct sockaddr_storage* addr, socklen_t addrlen,
22245872187Ssthen 	enum acl_access control)
22345872187Ssthen {
22445872187Ssthen 	return acl_find_or_create(acl_interface, addr, addrlen, control);
22545872187Ssthen }
22645872187Ssthen 
22777079be7Ssthen /** apply acl_tag string */
22877079be7Ssthen static int
acl_list_tags_cfg(struct acl_list * acl,const char * str,uint8_t * bitmap,size_t bitmaplen,int is_interface,int port)22977079be7Ssthen acl_list_tags_cfg(struct acl_list* acl, const char* str, uint8_t* bitmap,
23045872187Ssthen 	size_t bitmaplen, int is_interface, int port)
23177079be7Ssthen {
23277079be7Ssthen 	struct acl_addr* node;
23345872187Ssthen 	if(!(node=acl_find_or_create_str2addr(acl, str, is_interface, port))) {
23445872187Ssthen 		if(is_interface)
23545872187Ssthen 			log_err("non-configured interface: %s", str);
23677079be7Ssthen 		return 0;
23745872187Ssthen 	}
23877079be7Ssthen 	node->taglen = bitmaplen;
23977079be7Ssthen 	node->taglist = regional_alloc_init(acl->region, bitmap, bitmaplen);
24077079be7Ssthen 	if(!node->taglist) {
24177079be7Ssthen 		log_err("out of memory");
24277079be7Ssthen 		return 0;
24377079be7Ssthen 	}
24477079be7Ssthen 	return 1;
24577079be7Ssthen }
24677079be7Ssthen 
24777079be7Ssthen /** apply acl_view string */
24877079be7Ssthen static int
acl_list_view_cfg(struct acl_list * acl,const char * str,const char * str2,struct views * vs,int is_interface,int port)24977079be7Ssthen acl_list_view_cfg(struct acl_list* acl, const char* str, const char* str2,
25045872187Ssthen 	struct views* vs, int is_interface, int port)
25177079be7Ssthen {
25277079be7Ssthen 	struct acl_addr* node;
25345872187Ssthen 	if(!(node=acl_find_or_create_str2addr(acl, str, is_interface, port))) {
25445872187Ssthen 		if(is_interface)
25545872187Ssthen 			log_err("non-configured interface: %s", str);
25677079be7Ssthen 		return 0;
25745872187Ssthen 	}
25877079be7Ssthen 	node->view = views_find_view(vs, str2, 0 /* get read lock*/);
25977079be7Ssthen 	if(!node->view) {
26077079be7Ssthen 		log_err("no view with name: %s", str2);
26177079be7Ssthen 		return 0;
26277079be7Ssthen 	}
26377079be7Ssthen 	lock_rw_unlock(&node->view->lock);
26477079be7Ssthen 	return 1;
26577079be7Ssthen }
26677079be7Ssthen 
26777079be7Ssthen /** apply acl_tag_action string */
26877079be7Ssthen static int
acl_list_tag_action_cfg(struct acl_list * acl,struct config_file * cfg,const char * str,const char * tag,const char * action,int is_interface,int port)26977079be7Ssthen acl_list_tag_action_cfg(struct acl_list* acl, struct config_file* cfg,
27045872187Ssthen 	const char* str, const char* tag, const char* action,
27145872187Ssthen 	int is_interface, int port)
27277079be7Ssthen {
27377079be7Ssthen 	struct acl_addr* node;
27477079be7Ssthen 	int tagid;
27577079be7Ssthen 	enum localzone_type t;
27645872187Ssthen 	if(!(node=acl_find_or_create_str2addr(acl, str, is_interface, port))) {
27745872187Ssthen 		if(is_interface)
27845872187Ssthen 			log_err("non-configured interface: %s", str);
27977079be7Ssthen 		return 0;
28045872187Ssthen 	}
28177079be7Ssthen 	/* allocate array if not yet */
28277079be7Ssthen 	if(!node->tag_actions) {
28377079be7Ssthen 		node->tag_actions = (uint8_t*)regional_alloc_zero(acl->region,
28477079be7Ssthen 			sizeof(*node->tag_actions)*cfg->num_tags);
28577079be7Ssthen 		if(!node->tag_actions) {
28677079be7Ssthen 			log_err("out of memory");
28777079be7Ssthen 			return 0;
28877079be7Ssthen 		}
28977079be7Ssthen 		node->tag_actions_size = (size_t)cfg->num_tags;
29077079be7Ssthen 	}
29177079be7Ssthen 	/* parse tag */
29277079be7Ssthen 	if((tagid=find_tag_id(cfg, tag)) == -1) {
29377079be7Ssthen 		log_err("cannot parse tag (define-tag it): %s %s", str, tag);
29477079be7Ssthen 		return 0;
29577079be7Ssthen 	}
29677079be7Ssthen 	if((size_t)tagid >= node->tag_actions_size) {
29777079be7Ssthen 		log_err("tagid too large for array %s %s", str, tag);
29877079be7Ssthen 		return 0;
29977079be7Ssthen 	}
30077079be7Ssthen 	if(!local_zone_str2type(action, &t)) {
30177079be7Ssthen 		log_err("cannot parse access control action type: %s %s %s",
30277079be7Ssthen 			str, tag, action);
30377079be7Ssthen 		return 0;
30477079be7Ssthen 	}
30577079be7Ssthen 	node->tag_actions[tagid] = (uint8_t)t;
30677079be7Ssthen 	return 1;
30777079be7Ssthen }
30877079be7Ssthen 
30977079be7Ssthen /** check wire data parse */
31077079be7Ssthen static int
check_data(const char * data,const struct config_strlist * head)31177079be7Ssthen check_data(const char* data, const struct config_strlist* head)
31277079be7Ssthen {
31377079be7Ssthen 	char buf[65536];
31477079be7Ssthen 	uint8_t rr[LDNS_RR_BUF_SIZE];
31577079be7Ssthen 	size_t len = sizeof(rr);
31677079be7Ssthen 	int res;
31777079be7Ssthen 	/* '.' is sufficient for validation, and it makes the call to
31877079be7Ssthen 	 * sldns_wirerr_get_type() simpler below. */
31977079be7Ssthen 	snprintf(buf, sizeof(buf), "%s %s", ".", data);
32077079be7Ssthen 	res = sldns_str2wire_rr_buf(buf, rr, &len, NULL, 3600, NULL, 0,
32177079be7Ssthen 		NULL, 0);
32277079be7Ssthen 
32377079be7Ssthen 	/* Reject it if we would end up having CNAME and other data (including
32477079be7Ssthen 	 * another CNAME) for the same tag. */
32577079be7Ssthen 	if(res == 0 && head) {
32677079be7Ssthen 		const char* err_data = NULL;
32777079be7Ssthen 
32877079be7Ssthen 		if(sldns_wirerr_get_type(rr, len, 1) == LDNS_RR_TYPE_CNAME) {
32977079be7Ssthen 			/* adding CNAME while other data already exists. */
33077079be7Ssthen 			err_data = data;
33177079be7Ssthen 		} else {
33277079be7Ssthen 			snprintf(buf, sizeof(buf), "%s %s", ".", head->str);
33377079be7Ssthen 			len = sizeof(rr);
33477079be7Ssthen 			res = sldns_str2wire_rr_buf(buf, rr, &len, NULL, 3600,
33577079be7Ssthen 				NULL, 0, NULL, 0);
33677079be7Ssthen 			if(res != 0) {
33777079be7Ssthen 				/* This should be impossible here as head->str
33877079be7Ssthen 				 * has been validated, but we check it just in
33977079be7Ssthen 				 * case. */
34077079be7Ssthen 				return 0;
34177079be7Ssthen 			}
34277079be7Ssthen 			if(sldns_wirerr_get_type(rr, len, 1) ==
34377079be7Ssthen 				LDNS_RR_TYPE_CNAME) /* already have CNAME */
34477079be7Ssthen 				err_data = head->str;
34577079be7Ssthen 		}
34677079be7Ssthen 		if(err_data) {
34777079be7Ssthen 			log_err("redirect tag data '%s' must not coexist with "
34877079be7Ssthen 				"other data.", err_data);
34977079be7Ssthen 			return 0;
35077079be7Ssthen 		}
35177079be7Ssthen 	}
35277079be7Ssthen 	if(res == 0)
35377079be7Ssthen 		return 1;
35477079be7Ssthen 	log_err("rr data [char %d] parse error %s",
355a3167c07Ssthen 		(int)LDNS_WIREPARSE_OFFSET(res)-2,
35677079be7Ssthen 		sldns_get_errorstr_parse(res));
35777079be7Ssthen 	return 0;
35877079be7Ssthen }
35977079be7Ssthen 
36077079be7Ssthen /** apply acl_tag_data string */
36177079be7Ssthen static int
acl_list_tag_data_cfg(struct acl_list * acl,struct config_file * cfg,const char * str,const char * tag,const char * data,int is_interface,int port)36277079be7Ssthen acl_list_tag_data_cfg(struct acl_list* acl, struct config_file* cfg,
36345872187Ssthen 	const char* str, const char* tag, const char* data,
36445872187Ssthen 	int is_interface, int port)
36577079be7Ssthen {
36677079be7Ssthen 	struct acl_addr* node;
36777079be7Ssthen 	int tagid;
36877079be7Ssthen 	char* dupdata;
36945872187Ssthen 	if(!(node=acl_find_or_create_str2addr(acl, str, is_interface, port))) {
37045872187Ssthen 		if(is_interface)
37145872187Ssthen 			log_err("non-configured interface: %s", str);
37277079be7Ssthen 		return 0;
37345872187Ssthen 	}
37477079be7Ssthen 	/* allocate array if not yet */
37577079be7Ssthen 	if(!node->tag_datas) {
37677079be7Ssthen 		node->tag_datas = (struct config_strlist**)regional_alloc_zero(
37777079be7Ssthen 			acl->region, sizeof(*node->tag_datas)*cfg->num_tags);
37877079be7Ssthen 		if(!node->tag_datas) {
37977079be7Ssthen 			log_err("out of memory");
38077079be7Ssthen 			return 0;
38177079be7Ssthen 		}
38277079be7Ssthen 		node->tag_datas_size = (size_t)cfg->num_tags;
38377079be7Ssthen 	}
38477079be7Ssthen 	/* parse tag */
38577079be7Ssthen 	if((tagid=find_tag_id(cfg, tag)) == -1) {
38677079be7Ssthen 		log_err("cannot parse tag (define-tag it): %s %s", str, tag);
38777079be7Ssthen 		return 0;
38877079be7Ssthen 	}
38977079be7Ssthen 	if((size_t)tagid >= node->tag_datas_size) {
39077079be7Ssthen 		log_err("tagid too large for array %s %s", str, tag);
39177079be7Ssthen 		return 0;
39277079be7Ssthen 	}
39377079be7Ssthen 
39477079be7Ssthen 	/* check data? */
39577079be7Ssthen 	if(!check_data(data, node->tag_datas[tagid])) {
39677079be7Ssthen 		log_err("cannot parse access-control-tag data: %s %s '%s'",
39777079be7Ssthen 			str, tag, data);
39877079be7Ssthen 		return 0;
39977079be7Ssthen 	}
40077079be7Ssthen 
40177079be7Ssthen 	dupdata = regional_strdup(acl->region, data);
40277079be7Ssthen 	if(!dupdata) {
40377079be7Ssthen 		log_err("out of memory");
40477079be7Ssthen 		return 0;
40577079be7Ssthen 	}
40677079be7Ssthen 	if(!cfg_region_strlist_insert(acl->region,
40777079be7Ssthen 		&(node->tag_datas[tagid]), dupdata)) {
40877079be7Ssthen 		log_err("out of memory");
40977079be7Ssthen 		return 0;
41077079be7Ssthen 	}
41177079be7Ssthen 	return 1;
41277079be7Ssthen }
41377079be7Ssthen 
414933707f3Ssthen /** read acl_list config */
415933707f3Ssthen static int
read_acl_list(struct acl_list * acl,struct config_str2list * acls)41645872187Ssthen read_acl_list(struct acl_list* acl, struct config_str2list* acls)
417933707f3Ssthen {
418933707f3Ssthen 	struct config_str2list* p;
41945872187Ssthen 	for(p = acls; p; p = p->next) {
420933707f3Ssthen 		log_assert(p->str && p->str2);
421933707f3Ssthen 		if(!acl_list_str_cfg(acl, p->str, p->str2, 1))
422933707f3Ssthen 			return 0;
423933707f3Ssthen 	}
424933707f3Ssthen 	return 1;
425933707f3Ssthen }
426933707f3Ssthen 
42745872187Ssthen /** read acl view config */
42877079be7Ssthen static int
read_acl_view(struct acl_list * acl,struct config_str2list ** acl_view,struct views * v)42945872187Ssthen read_acl_view(struct acl_list* acl, struct config_str2list** acl_view,
43045872187Ssthen 	struct views* v)
43177079be7Ssthen {
43245872187Ssthen 	struct config_str2list* np, *p = *acl_view;
43345872187Ssthen 	*acl_view = NULL;
43477079be7Ssthen 	while(p) {
43577079be7Ssthen 		log_assert(p->str && p->str2);
43645872187Ssthen 		if(!acl_list_view_cfg(acl, p->str, p->str2, v, 0, 0)) {
43745872187Ssthen 			config_deldblstrlist(p);
43877079be7Ssthen 			return 0;
43977079be7Ssthen 		}
44077079be7Ssthen 		/* free the items as we go to free up memory */
44177079be7Ssthen 		np = p->next;
44277079be7Ssthen 		free(p->str);
44377079be7Ssthen 		free(p->str2);
44477079be7Ssthen 		free(p);
44577079be7Ssthen 		p = np;
44677079be7Ssthen 	}
44777079be7Ssthen 	return 1;
44877079be7Ssthen }
44977079be7Ssthen 
45045872187Ssthen /** read acl tags config */
45177079be7Ssthen static int
read_acl_tags(struct acl_list * acl,struct config_strbytelist ** acl_tags)45245872187Ssthen read_acl_tags(struct acl_list* acl, struct config_strbytelist** acl_tags)
45377079be7Ssthen {
45445872187Ssthen 	struct config_strbytelist* np, *p = *acl_tags;
45545872187Ssthen 	*acl_tags = NULL;
45677079be7Ssthen 	while(p) {
45777079be7Ssthen 		log_assert(p->str && p->str2);
45845872187Ssthen 		if(!acl_list_tags_cfg(acl, p->str, p->str2, p->str2len, 0, 0)) {
45945872187Ssthen 			config_del_strbytelist(p);
46077079be7Ssthen 			return 0;
46177079be7Ssthen 		}
46277079be7Ssthen 		/* free the items as we go to free up memory */
46377079be7Ssthen 		np = p->next;
46477079be7Ssthen 		free(p->str);
46577079be7Ssthen 		free(p->str2);
46677079be7Ssthen 		free(p);
46777079be7Ssthen 		p = np;
46877079be7Ssthen 	}
46977079be7Ssthen 	return 1;
47077079be7Ssthen }
47177079be7Ssthen 
47277079be7Ssthen /** read acl tag actions config */
47377079be7Ssthen static int
read_acl_tag_actions(struct acl_list * acl,struct config_file * cfg,struct config_str3list ** acl_tag_actions)47445872187Ssthen read_acl_tag_actions(struct acl_list* acl, struct config_file* cfg,
47545872187Ssthen 	struct config_str3list** acl_tag_actions)
47677079be7Ssthen {
47777079be7Ssthen 	struct config_str3list* p, *np;
47845872187Ssthen 	p = *acl_tag_actions;
47945872187Ssthen 	*acl_tag_actions = NULL;
48077079be7Ssthen 	while(p) {
48177079be7Ssthen 		log_assert(p->str && p->str2 && p->str3);
48277079be7Ssthen 		if(!acl_list_tag_action_cfg(acl, cfg, p->str, p->str2,
48345872187Ssthen 			p->str3, 0, 0)) {
48477079be7Ssthen 			config_deltrplstrlist(p);
48577079be7Ssthen 			return 0;
48677079be7Ssthen 		}
48777079be7Ssthen 		/* free the items as we go to free up memory */
48877079be7Ssthen 		np = p->next;
48977079be7Ssthen 		free(p->str);
49077079be7Ssthen 		free(p->str2);
49177079be7Ssthen 		free(p->str3);
49277079be7Ssthen 		free(p);
49377079be7Ssthen 		p = np;
49477079be7Ssthen 	}
49577079be7Ssthen 	return 1;
49677079be7Ssthen }
49777079be7Ssthen 
49877079be7Ssthen /** read acl tag datas config */
49977079be7Ssthen static int
read_acl_tag_datas(struct acl_list * acl,struct config_file * cfg,struct config_str3list ** acl_tag_datas)50045872187Ssthen read_acl_tag_datas(struct acl_list* acl, struct config_file* cfg,
50145872187Ssthen 	struct config_str3list** acl_tag_datas)
50277079be7Ssthen {
50377079be7Ssthen 	struct config_str3list* p, *np;
50445872187Ssthen 	p = *acl_tag_datas;
50545872187Ssthen 	*acl_tag_datas = NULL;
50677079be7Ssthen 	while(p) {
50777079be7Ssthen 		log_assert(p->str && p->str2 && p->str3);
50845872187Ssthen 		if(!acl_list_tag_data_cfg(acl, cfg, p->str, p->str2, p->str3,
50945872187Ssthen 			0, 0)) {
51077079be7Ssthen 			config_deltrplstrlist(p);
51177079be7Ssthen 			return 0;
51277079be7Ssthen 		}
51377079be7Ssthen 		/* free the items as we go to free up memory */
51477079be7Ssthen 		np = p->next;
51577079be7Ssthen 		free(p->str);
51677079be7Ssthen 		free(p->str2);
51777079be7Ssthen 		free(p->str3);
51877079be7Ssthen 		free(p);
51977079be7Ssthen 		p = np;
52077079be7Ssthen 	}
52177079be7Ssthen 	return 1;
52277079be7Ssthen }
52377079be7Ssthen 
524933707f3Ssthen int
acl_list_apply_cfg(struct acl_list * acl,struct config_file * cfg,struct views * v)52577079be7Ssthen acl_list_apply_cfg(struct acl_list* acl, struct config_file* cfg,
52677079be7Ssthen 	struct views* v)
527933707f3Ssthen {
528933707f3Ssthen 	regional_free_all(acl->region);
529933707f3Ssthen 	addr_tree_init(&acl->tree);
53045872187Ssthen 	if(!read_acl_list(acl, cfg->acls))
531933707f3Ssthen 		return 0;
53245872187Ssthen 	if(!read_acl_view(acl, &cfg->acl_view, v))
53377079be7Ssthen 		return 0;
53445872187Ssthen 	if(!read_acl_tags(acl, &cfg->acl_tags))
53577079be7Ssthen 		return 0;
53645872187Ssthen 	if(!read_acl_tag_actions(acl, cfg, &cfg->acl_tag_actions))
53777079be7Ssthen 		return 0;
53845872187Ssthen 	if(!read_acl_tag_datas(acl, cfg, &cfg->acl_tag_datas))
53977079be7Ssthen 		return 0;
540933707f3Ssthen 	/* insert defaults, with '0' to ignore them if they are duplicates */
54145872187Ssthen 	/* the 'refuse' defaults for /0 are now done per interface instead */
542933707f3Ssthen 	if(!acl_list_str_cfg(acl, "127.0.0.0/8", "allow", 0))
543933707f3Ssthen 		return 0;
544933707f3Ssthen 	if(cfg->do_ip6) {
545933707f3Ssthen 		if(!acl_list_str_cfg(acl, "::1", "allow", 0))
546933707f3Ssthen 			return 0;
547933707f3Ssthen 		if(!acl_list_str_cfg(acl, "::ffff:127.0.0.1", "allow", 0))
548933707f3Ssthen 			return 0;
549933707f3Ssthen 	}
550933707f3Ssthen 	addr_tree_init_parents(&acl->tree);
551933707f3Ssthen 	return 1;
552933707f3Ssthen }
553933707f3Ssthen 
55445872187Ssthen int
acl_interface_compare(const void * k1,const void * k2)55545872187Ssthen acl_interface_compare(const void* k1, const void* k2)
55645872187Ssthen {
55745872187Ssthen 	struct addr_tree_node* n1 = (struct addr_tree_node*)k1;
55845872187Ssthen 	struct addr_tree_node* n2 = (struct addr_tree_node*)k2;
55945872187Ssthen 	return sockaddr_cmp(&n1->addr, n1->addrlen, &n2->addr,
56045872187Ssthen 		n2->addrlen);
56145872187Ssthen 	/* We don't care about comparing node->net. All addresses in the
56245872187Ssthen 	 * acl_interface tree have either 32 (ipv4) or 128 (ipv6). */
56345872187Ssthen }
56445872187Ssthen 
56545872187Ssthen void
acl_interface_init(struct acl_list * acl_interface)56645872187Ssthen acl_interface_init(struct acl_list* acl_interface)
56745872187Ssthen {
56845872187Ssthen 	regional_free_all(acl_interface->region);
56945872187Ssthen 	/* We want comparison in the tree to include only address and port.
57045872187Ssthen 	 * We don't care about comparing node->net. All addresses in the
57145872187Ssthen 	 * acl_interface->tree should have either 32 (ipv4) or 128 (ipv6).
57245872187Ssthen 	 * Initialise with the appropriate compare function but keep treating
57345872187Ssthen 	 * it as an addr_tree. */
57445872187Ssthen 	addr_tree_addrport_init(&acl_interface->tree);
57545872187Ssthen }
57645872187Ssthen 
57745872187Ssthen static int
read_acl_interface_action(struct acl_list * acl_interface,struct config_str2list * acls,int port)57845872187Ssthen read_acl_interface_action(struct acl_list* acl_interface,
57945872187Ssthen 	struct config_str2list* acls, int port)
58045872187Ssthen {
58145872187Ssthen 	struct config_str2list* p;
58245872187Ssthen 	for(p = acls; p; p = p->next) {
58345872187Ssthen 		char** resif = NULL;
58445872187Ssthen 		int num_resif = 0;
58545872187Ssthen 		int i;
58645872187Ssthen 		log_assert(p->str && p->str2);
58745872187Ssthen 		if(!resolve_interface_names(&p->str, 1, NULL, &resif, &num_resif))
58845872187Ssthen 			return 0;
58945872187Ssthen 		for(i = 0; i<num_resif; i++) {
59045872187Ssthen 			if(!acl_interface_str_cfg(acl_interface, resif[i], p->str2, port)){
59145872187Ssthen 				config_del_strarray(resif, num_resif);
59245872187Ssthen 				return 0;
59345872187Ssthen 			}
59445872187Ssthen 		}
59545872187Ssthen 		config_del_strarray(resif, num_resif);
59645872187Ssthen 	}
59745872187Ssthen 	return 1;
59845872187Ssthen }
59945872187Ssthen 
60045872187Ssthen /** read acl view config for interface */
60145872187Ssthen static int
read_acl_interface_view(struct acl_list * acl_interface,struct config_str2list ** acl_view,struct views * v,int port)60245872187Ssthen read_acl_interface_view(struct acl_list* acl_interface,
60345872187Ssthen 	struct config_str2list** acl_view,
60445872187Ssthen 	struct views* v, int port)
60545872187Ssthen {
60645872187Ssthen 	struct config_str2list* np, *p = *acl_view;
60745872187Ssthen 	*acl_view = NULL;
60845872187Ssthen 	while(p) {
60945872187Ssthen 		char** resif = NULL;
61045872187Ssthen 		int num_resif = 0;
61145872187Ssthen 		int i;
61245872187Ssthen 		log_assert(p->str && p->str2);
61345872187Ssthen 		if(!resolve_interface_names(&p->str, 1, NULL, &resif, &num_resif)) {
61445872187Ssthen 			config_deldblstrlist(p);
61545872187Ssthen 			return 0;
61645872187Ssthen 		}
61745872187Ssthen 		for(i = 0; i<num_resif; i++) {
61845872187Ssthen 			if(!acl_list_view_cfg(acl_interface, resif[i], p->str2,
61945872187Ssthen 				v, 1, port)) {
62045872187Ssthen 				config_del_strarray(resif, num_resif);
62145872187Ssthen 				config_deldblstrlist(p);
62245872187Ssthen 				return 0;
62345872187Ssthen 			}
62445872187Ssthen 		}
62545872187Ssthen 		config_del_strarray(resif, num_resif);
62645872187Ssthen 		/* free the items as we go to free up memory */
62745872187Ssthen 		np = p->next;
62845872187Ssthen 		free(p->str);
62945872187Ssthen 		free(p->str2);
63045872187Ssthen 		free(p);
63145872187Ssthen 		p = np;
63245872187Ssthen 	}
63345872187Ssthen 	return 1;
63445872187Ssthen }
63545872187Ssthen 
63645872187Ssthen /** read acl tags config for interface */
63745872187Ssthen static int
read_acl_interface_tags(struct acl_list * acl_interface,struct config_strbytelist ** acl_tags,int port)63845872187Ssthen read_acl_interface_tags(struct acl_list* acl_interface,
63945872187Ssthen 	struct config_strbytelist** acl_tags, int port)
64045872187Ssthen {
64145872187Ssthen 	struct config_strbytelist* np, *p = *acl_tags;
64245872187Ssthen 	*acl_tags = NULL;
64345872187Ssthen 	while(p) {
64445872187Ssthen 		char** resif = NULL;
64545872187Ssthen 		int num_resif = 0;
64645872187Ssthen 		int i;
64745872187Ssthen 		log_assert(p->str && p->str2);
64845872187Ssthen 		if(!resolve_interface_names(&p->str, 1, NULL, &resif, &num_resif)) {
64945872187Ssthen 			config_del_strbytelist(p);
65045872187Ssthen 			return 0;
65145872187Ssthen 		}
65245872187Ssthen 		for(i = 0; i<num_resif; i++) {
65345872187Ssthen 			if(!acl_list_tags_cfg(acl_interface, resif[i], p->str2,
65445872187Ssthen 				p->str2len, 1, port)) {
65545872187Ssthen 				config_del_strbytelist(p);
65645872187Ssthen 				config_del_strarray(resif, num_resif);
65745872187Ssthen 				return 0;
65845872187Ssthen 			}
65945872187Ssthen 		}
66045872187Ssthen 		config_del_strarray(resif, num_resif);
66145872187Ssthen 		/* free the items as we go to free up memory */
66245872187Ssthen 		np = p->next;
66345872187Ssthen 		free(p->str);
66445872187Ssthen 		free(p->str2);
66545872187Ssthen 		free(p);
66645872187Ssthen 		p = np;
66745872187Ssthen 	}
66845872187Ssthen 	return 1;
66945872187Ssthen }
67045872187Ssthen 
67145872187Ssthen /** read acl tag actions config for interface*/
67245872187Ssthen static int
read_acl_interface_tag_actions(struct acl_list * acl_interface,struct config_file * cfg,struct config_str3list ** acl_tag_actions,int port)67345872187Ssthen read_acl_interface_tag_actions(struct acl_list* acl_interface,
67445872187Ssthen 	struct config_file* cfg,
67545872187Ssthen 	struct config_str3list** acl_tag_actions, int port)
67645872187Ssthen {
67745872187Ssthen 	struct config_str3list* p, *np;
67845872187Ssthen 	p = *acl_tag_actions;
67945872187Ssthen 	*acl_tag_actions = NULL;
68045872187Ssthen 	while(p) {
68145872187Ssthen 		char** resif = NULL;
68245872187Ssthen 		int num_resif = 0;
68345872187Ssthen 		int i;
68445872187Ssthen 		log_assert(p->str && p->str2 && p->str3);
68545872187Ssthen 		if(!resolve_interface_names(&p->str, 1, NULL, &resif, &num_resif)) {
68645872187Ssthen 			config_deltrplstrlist(p);
68745872187Ssthen 			return 0;
68845872187Ssthen 		}
68945872187Ssthen 		for(i = 0; i<num_resif; i++) {
69045872187Ssthen 			if(!acl_list_tag_action_cfg(acl_interface, cfg,
69145872187Ssthen 				resif[i], p->str2, p->str3, 1, port)) {
69245872187Ssthen 				config_deltrplstrlist(p);
69345872187Ssthen 				config_del_strarray(resif, num_resif);
69445872187Ssthen 				return 0;
69545872187Ssthen 			}
69645872187Ssthen 		}
69745872187Ssthen 		config_del_strarray(resif, num_resif);
69845872187Ssthen 		/* free the items as we go to free up memory */
69945872187Ssthen 		np = p->next;
70045872187Ssthen 		free(p->str);
70145872187Ssthen 		free(p->str2);
70245872187Ssthen 		free(p->str3);
70345872187Ssthen 		free(p);
70445872187Ssthen 		p = np;
70545872187Ssthen 	}
70645872187Ssthen 	return 1;
70745872187Ssthen }
70845872187Ssthen 
70945872187Ssthen /** read acl tag datas config for interface */
71045872187Ssthen static int
read_acl_interface_tag_datas(struct acl_list * acl_interface,struct config_file * cfg,struct config_str3list ** acl_tag_datas,int port)71145872187Ssthen read_acl_interface_tag_datas(struct acl_list* acl_interface,
71245872187Ssthen 	struct config_file* cfg,
71345872187Ssthen 	struct config_str3list** acl_tag_datas, int port)
71445872187Ssthen {
71545872187Ssthen 	struct config_str3list* p, *np;
71645872187Ssthen 	p = *acl_tag_datas;
71745872187Ssthen 	*acl_tag_datas = NULL;
71845872187Ssthen 	while(p) {
71945872187Ssthen 		char** resif = NULL;
72045872187Ssthen 		int num_resif = 0;
72145872187Ssthen 		int i;
72245872187Ssthen 		log_assert(p->str && p->str2 && p->str3);
72345872187Ssthen 		if(!resolve_interface_names(&p->str, 1, NULL, &resif, &num_resif)) {
72445872187Ssthen 			config_deltrplstrlist(p);
72545872187Ssthen 			return 0;
72645872187Ssthen 		}
72745872187Ssthen 		for(i = 0; i<num_resif; i++) {
72845872187Ssthen 			if(!acl_list_tag_data_cfg(acl_interface, cfg,
72945872187Ssthen 				resif[i], p->str2, p->str3, 1, port)) {
73045872187Ssthen 				config_deltrplstrlist(p);
73145872187Ssthen 				config_del_strarray(resif, num_resif);
73245872187Ssthen 				return 0;
73345872187Ssthen 			}
73445872187Ssthen 		}
73545872187Ssthen 		config_del_strarray(resif, num_resif);
73645872187Ssthen 		/* free the items as we go to free up memory */
73745872187Ssthen 		np = p->next;
73845872187Ssthen 		free(p->str);
73945872187Ssthen 		free(p->str2);
74045872187Ssthen 		free(p->str3);
74145872187Ssthen 		free(p);
74245872187Ssthen 		p = np;
74345872187Ssthen 	}
74445872187Ssthen 	return 1;
74545872187Ssthen }
74645872187Ssthen 
74745872187Ssthen int
acl_interface_apply_cfg(struct acl_list * acl_interface,struct config_file * cfg,struct views * v)74845872187Ssthen acl_interface_apply_cfg(struct acl_list* acl_interface, struct config_file* cfg,
74945872187Ssthen 	struct views* v)
75045872187Ssthen {
75145872187Ssthen 	if(!read_acl_interface_action(acl_interface, cfg->interface_actions,
75245872187Ssthen 		cfg->port))
75345872187Ssthen 		return 0;
75445872187Ssthen 	if(!read_acl_interface_view(acl_interface, &cfg->interface_view, v,
75545872187Ssthen 		cfg->port))
75645872187Ssthen 		return 0;
75745872187Ssthen 	if(!read_acl_interface_tags(acl_interface, &cfg->interface_tags,
75845872187Ssthen 		cfg->port))
75945872187Ssthen 		return 0;
76045872187Ssthen 	if(!read_acl_interface_tag_actions(acl_interface, cfg,
76145872187Ssthen 		&cfg->interface_tag_actions, cfg->port))
76245872187Ssthen 		return 0;
76345872187Ssthen 	if(!read_acl_interface_tag_datas(acl_interface, cfg,
76445872187Ssthen 		&cfg->interface_tag_datas, cfg->port))
76545872187Ssthen 		return 0;
76645872187Ssthen 	addr_tree_init_parents(&acl_interface->tree);
76745872187Ssthen 	return 1;
76845872187Ssthen }
76945872187Ssthen 
770933707f3Ssthen enum acl_access
acl_get_control(struct acl_addr * acl)77177079be7Ssthen acl_get_control(struct acl_addr* acl)
77277079be7Ssthen {
77377079be7Ssthen 	if(acl) return acl->control;
77477079be7Ssthen 	return acl_deny;
77577079be7Ssthen }
77677079be7Ssthen 
77777079be7Ssthen struct acl_addr*
acl_addr_lookup(struct acl_list * acl,struct sockaddr_storage * addr,socklen_t addrlen)77877079be7Ssthen acl_addr_lookup(struct acl_list* acl, struct sockaddr_storage* addr,
779933707f3Ssthen         socklen_t addrlen)
780933707f3Ssthen {
78177079be7Ssthen 	return (struct acl_addr*)addr_tree_lookup(&acl->tree,
782933707f3Ssthen 		addr, addrlen);
783933707f3Ssthen }
784933707f3Ssthen 
785933707f3Ssthen size_t
acl_list_get_mem(struct acl_list * acl)786933707f3Ssthen acl_list_get_mem(struct acl_list* acl)
787933707f3Ssthen {
788933707f3Ssthen 	if(!acl) return 0;
789933707f3Ssthen 	return sizeof(*acl) + regional_get_mem(acl->region);
790933707f3Ssthen }
7910bdb4f62Ssthen 
acl_access_to_str(enum acl_access acl)7920bdb4f62Ssthen const char* acl_access_to_str(enum acl_access acl)
7930bdb4f62Ssthen {
7940bdb4f62Ssthen 	switch(acl) {
7950bdb4f62Ssthen 	case acl_deny: return "deny";
7960bdb4f62Ssthen 	case acl_refuse: return "refuse";
7970bdb4f62Ssthen 	case acl_deny_non_local: return "deny_non_local";
7980bdb4f62Ssthen 	case acl_refuse_non_local: return "refuse_non_local";
7990bdb4f62Ssthen 	case acl_allow: return "allow";
8000bdb4f62Ssthen 	case acl_allow_snoop: return "allow_snoop";
8010bdb4f62Ssthen 	case acl_allow_setrd: return "allow_setrd";
8020bdb4f62Ssthen 	default: break;
8030bdb4f62Ssthen 	}
8040bdb4f62Ssthen 	return "unknown";
8050bdb4f62Ssthen }
8060bdb4f62Ssthen 
8070bdb4f62Ssthen void
log_acl_action(const char * action,struct sockaddr_storage * addr,socklen_t addrlen,enum acl_access acl,struct acl_addr * acladdr)8080bdb4f62Ssthen log_acl_action(const char* action, struct sockaddr_storage* addr,
8090bdb4f62Ssthen 	socklen_t addrlen, enum acl_access acl, struct acl_addr* acladdr)
8100bdb4f62Ssthen {
8110bdb4f62Ssthen 	char a[128], n[128];
8120bdb4f62Ssthen 	uint16_t port;
8130bdb4f62Ssthen 	addr_to_str(addr, addrlen, a, sizeof(a));
8140bdb4f62Ssthen 	port = ntohs(((struct sockaddr_in*)addr)->sin_port);
8150bdb4f62Ssthen 	if(acladdr) {
8160bdb4f62Ssthen 		addr_to_str(&acladdr->node.addr, acladdr->node.addrlen,
8170bdb4f62Ssthen 			n, sizeof(n));
8180bdb4f62Ssthen 		verbose(VERB_ALGO, "%s query from %s port %d because of "
8190bdb4f62Ssthen 			"%s/%d %s", action, a, (int)port, n, acladdr->node.net,
8200bdb4f62Ssthen 			acl_access_to_str(acl));
8210bdb4f62Ssthen 	} else {
8220bdb4f62Ssthen 		verbose(VERB_ALGO, "%s query from %s port %d", action, a,
8230bdb4f62Ssthen 			(int)port);
8240bdb4f62Ssthen 	}
8250bdb4f62Ssthen }
826