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*
acl_list_create(void)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
acl_list_delete(struct acl_list * acl)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*
acl_list_insert(struct acl_list * acl,struct sockaddr_storage * addr,socklen_t addrlen,int net,enum acl_access control,int complain_duplicates)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
parse_acl_access(const char * str,enum acl_access * control)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
acl_list_str_cfg(struct acl_list * acl,const char * str,const char * s2,int complain_duplicates)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*
acl_find_or_create_str2addr(struct acl_list * acl,const char * str,int is_interface,int port)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*
acl_find_or_create(struct acl_list * acl,struct sockaddr_storage * addr,socklen_t addrlen,enum acl_access control)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
acl_interface_str_cfg(struct acl_list * acl_interface,const char * iface,const char * s2,int port)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*
acl_interface_insert(struct acl_list * acl_interface,struct sockaddr_storage * addr,socklen_t addrlen,enum acl_access control)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
acl_list_tags_cfg(struct acl_list * acl,const char * str,uint8_t * bitmap,size_t bitmaplen,int is_interface,int port)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
acl_list_view_cfg(struct acl_list * acl,const char * str,const char * str2,struct views * vs,int is_interface,int port)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
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)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
check_data(const char * data,const struct config_strlist * head)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
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)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
read_acl_list(struct acl_list * acl,struct config_str2list * acls)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
read_acl_view(struct acl_list * acl,struct config_str2list ** acl_view,struct views * v)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
read_acl_tags(struct acl_list * acl,struct config_strbytelist ** acl_tags)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
read_acl_tag_actions(struct acl_list * acl,struct config_file * cfg,struct config_str3list ** acl_tag_actions)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
read_acl_tag_datas(struct acl_list * acl,struct config_file * cfg,struct config_str3list ** acl_tag_datas)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
acl_list_apply_cfg(struct acl_list * acl,struct config_file * cfg,struct views * v)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
acl_interface_init(struct acl_list * acl_interface)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
read_acl_interface_action(struct acl_list * acl_interface,struct config_str2list * acls,int port)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
read_acl_interface_view(struct acl_list * acl_interface,struct config_str2list ** acl_view,struct views * v,int port)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
read_acl_interface_tags(struct acl_list * acl_interface,struct config_strbytelist ** acl_tags,int port)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
read_acl_interface_tag_actions(struct acl_list * acl_interface,struct config_file * cfg,struct config_str3list ** acl_tag_actions,int port)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
read_acl_interface_tag_datas(struct acl_list * acl_interface,struct config_file * cfg,struct config_str3list ** acl_tag_datas,int port)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
acl_interface_apply_cfg(struct acl_list * acl_interface,struct config_file * cfg,struct views * v)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
acl_get_control(struct acl_addr * acl)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*
acl_addr_lookup(struct acl_list * acl,struct sockaddr_storage * addr,socklen_t addrlen)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
acl_list_get_mem(struct acl_list * acl)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
acl_access_to_str(enum acl_access acl)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
log_acl_action(const char * action,struct sockaddr_storage * addr,socklen_t addrlen,enum acl_access acl,struct acl_addr * acladdr)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
acl_list_swap_tree(struct acl_list * acl,struct acl_list * data)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