From: George Thessalonikefs Date: Sun, 11 Sep 2022 18:57:41 +0000 (+0200) Subject: - ACL per interface: refactor, complete testing and a bugfix for X-Git-Tag: release-1.17.0rc1~26^2~1 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=d301bfe4a2b005b0202b2e6cde6dd5fffe25239d;p=thirdparty%2Funbound.git - ACL per interface: refactor, complete testing and a bugfix for interface names. --- diff --git a/Makefile.in b/Makefile.in index bf78a694d..3189731ad 100644 --- a/Makefile.in +++ b/Makefile.in @@ -139,7 +139,7 @@ validator/val_sigcrypt.c validator/val_utils.c dns64/dns64.c \ edns-subnet/edns-subnet.c edns-subnet/subnetmod.c \ edns-subnet/addrtree.c edns-subnet/subnet-whitelist.c \ $(CACHEDB_SRC) respip/respip.c $(CHECKLOCK_SRC) \ -$(DNSTAP_SRC) $(DNSCRYPT_SRC) $(IPSECMOD_SRC) $(IPSET_SRC) daemon/acl_list.c +$(DNSTAP_SRC) $(DNSCRYPT_SRC) $(IPSECMOD_SRC) $(IPSET_SRC) COMMON_OBJ_WITHOUT_NETCALL=dns.lo infra.lo rrset.lo dname.lo msgencode.lo \ as112.lo msgparse.lo msgreply.lo packed_rrset.lo iterator.lo iter_delegpt.lo \ iter_donotq.lo iter_fwd.lo iter_hints.lo iter_priv.lo iter_resptype.lo \ @@ -154,7 +154,7 @@ val_secalgo.lo val_sigcrypt.lo val_utils.lo dns64.lo $(CACHEDB_OBJ) authzone.lo $(SUBNET_OBJ) $(PYTHONMOD_OBJ) $(CHECKLOCK_OBJ) $(DNSTAP_OBJ) $(DNSCRYPT_OBJ) \ $(IPSECMOD_OBJ) $(IPSET_OBJ) $(DYNLIBMOD_OBJ) respip.lo COMMON_OBJ_WITHOUT_UB_EVENT=$(COMMON_OBJ_WITHOUT_NETCALL) netevent.lo listen_dnsport.lo \ -outside_network.lo acl_list.lo +outside_network.lo COMMON_OBJ=$(COMMON_OBJ_WITHOUT_UB_EVENT) ub_event.lo # set to $COMMON_OBJ or to "" if --enableallsymbols COMMON_OBJ_ALL_SYMBOLS=@COMMON_OBJ_ALL_SYMBOLS@ @@ -186,9 +186,9 @@ readhex.lo testpkts.lo unitldns.lo unitecs.lo unitauth.lo unitzonemd.lo \ unittcpreuse.lo UNITTEST_OBJ_LINK=$(UNITTEST_OBJ) worker_cb.lo $(COMMON_OBJ) $(SLDNS_OBJ) \ $(COMPAT_OBJ) -DAEMON_SRC=daemon/cachedump.c daemon/daemon.c \ +DAEMON_SRC=daemon/acl_list.c daemon/cachedump.c daemon/daemon.c \ daemon/remote.c daemon/stats.c daemon/unbound.c daemon/worker.c @WIN_DAEMON_SRC@ -DAEMON_OBJ=cachedump.lo daemon.lo \ +DAEMON_OBJ=acl_list.lo cachedump.lo daemon.lo \ shm_main.lo remote.lo stats.lo unbound.lo \ worker.lo @WIN_DAEMON_OBJ@ DAEMON_OBJ_LINK=$(DAEMON_OBJ) $(COMMON_OBJ_ALL_SYMBOLS) $(SLDNS_OBJ) \ diff --git a/daemon/acl_list.c b/daemon/acl_list.c index 5ec4122a4..05b720bd5 100644 --- a/daemon/acl_list.c +++ b/daemon/acl_list.c @@ -142,8 +142,8 @@ acl_list_str_cfg(struct acl_list* acl, const char* str, const char* s2, /** find or create node (NULL on parse or error) */ static struct acl_addr* -acl_find_or_create(struct acl_list* acl, const char* str, int is_interface, - int port) +acl_find_or_create_str2addr(struct acl_list* acl, const char* str, + int is_interface, int port) { struct acl_addr* node; struct sockaddr_storage addr; @@ -174,6 +174,27 @@ acl_find_or_create(struct acl_list* acl, const char* str, int is_interface, return node; } +/** find or create node (NULL on error) */ +static struct acl_addr* +acl_find_or_create(struct acl_list* acl, struct sockaddr_storage* addr, + socklen_t addrlen, enum acl_access control) +{ + struct acl_addr* node; + int net = (addr_is_ip6(addr, addrlen)?128:32); + /* find or create node */ + if(!(node=(struct acl_addr*)addr_tree_find(&acl->tree, addr, + addrlen, net))) { + /* create node; + * can override with specific access-control: cfg */ + if(!(node=(struct acl_addr*)acl_list_insert(acl, addr, + addrlen, net, control, 1))) { + log_err("out of memory"); + return NULL; + } + } + return node; +} + /** apply acl_interface string */ static int acl_interface_str_cfg(struct acl_list* acl_interface, const char* interface, @@ -184,7 +205,7 @@ acl_interface_str_cfg(struct acl_list* acl_interface, const char* interface, if(!parse_acl_access(s2, &control)) { return 0; } - if(!(node=acl_find_or_create(acl_interface, interface, 1, port))) { + if(!(node=acl_find_or_create_str2addr(acl_interface, interface, 1, port))) { log_err("cannot update ACL on non-configured interface: %s %d", interface, port); return 0; @@ -194,25 +215,11 @@ acl_interface_str_cfg(struct acl_list* acl_interface, const char* interface, } struct acl_addr* -acl_interface_insert(struct acl_list* acl_interface, const char* interface, - const char* s2, int port) +acl_interface_insert(struct acl_list* acl_interface, + struct sockaddr_storage* addr, socklen_t addrlen, + enum acl_access control) { - struct acl_addr* node; - struct sockaddr_storage addr; - socklen_t addrlen; - enum acl_access control; - int net = (str_is_ip6(interface)?128:32); - if(!parse_acl_access(s2, &control)) { - return NULL; - } - if((node=acl_find_or_create(acl_interface, interface, 1, port))) { - return node; - } - if(!extstrtoaddr(interface, &addr, &addrlen, port)) { - log_err("cannot parse access control: %s %s", interface, s2); - return NULL; - } - return acl_list_insert(acl_interface, &addr, addrlen, net, control, 1); + return acl_find_or_create(acl_interface, addr, addrlen, control); } /** apply acl_tag string */ @@ -221,7 +228,7 @@ acl_list_tags_cfg(struct acl_list* acl, const char* str, uint8_t* bitmap, size_t bitmaplen, int is_interface, int port) { struct acl_addr* node; - if(!(node=acl_find_or_create(acl, str, is_interface, port))) { + if(!(node=acl_find_or_create_str2addr(acl, str, is_interface, port))) { if(is_interface) log_err("non-configured interface: %s", str); return 0; @@ -241,7 +248,7 @@ acl_list_view_cfg(struct acl_list* acl, const char* str, const char* str2, struct views* vs, int is_interface, int port) { struct acl_addr* node; - if(!(node=acl_find_or_create(acl, str, is_interface, port))) { + if(!(node=acl_find_or_create_str2addr(acl, str, is_interface, port))) { if(is_interface) log_err("non-configured interface: %s", str); return 0; @@ -264,7 +271,7 @@ acl_list_tag_action_cfg(struct acl_list* acl, struct config_file* cfg, struct acl_addr* node; int tagid; enum localzone_type t; - if(!(node=acl_find_or_create(acl, str, is_interface, port))) { + if(!(node=acl_find_or_create_str2addr(acl, str, is_interface, port))) { if(is_interface) log_err("non-configured interface: %s", str); return 0; @@ -357,7 +364,7 @@ acl_list_tag_data_cfg(struct acl_list* acl, struct config_file* cfg, struct acl_addr* node; int tagid; char* dupdata; - if(!(node=acl_find_or_create(acl, str, is_interface, port))) { + if(!(node=acl_find_or_create_str2addr(acl, str, is_interface, port))) { if(is_interface) log_err("non-configured interface: %s", str); return 0; @@ -557,10 +564,12 @@ void acl_interface_init(struct acl_list* acl_interface) { regional_free_all(acl_interface->region); - /* We want comparison in the tree to include both IP and port. - * Initialise with the given compare fucntion but keep treating it as - * an addr_tree. */ - rbtree_init(&acl_interface->tree, &acl_interface_compare); + /* We want comparison in the tree to include only address and port. + * We don't care about comparing node->net. All addresses in the + * acl_interface->tree should have either 32 (ipv4) or 128 (ipv6). + * Initialise with the appropriate compare fucntion but keep treating + * it as an addr_tree. */ + addr_tree_addrport_init(&acl_interface->tree); } static int @@ -604,7 +613,7 @@ read_acl_interface_view(struct acl_list* acl_interface, return 0; } for(i = 0; istr, p->str2, + if(!acl_list_view_cfg(acl_interface, resif[i], p->str2, v, 1, port)) { config_del_strarray(resif, num_resif); config_deldblstrlist(p); @@ -639,7 +648,7 @@ read_acl_interface_tags(struct acl_list* acl_interface, return 0; } for(i = 0; istr, p->str2, + if(!acl_list_tags_cfg(acl_interface, resif[i], p->str2, p->str2len, 1, port)) { config_del_strbytelist(p); config_del_strarray(resif, num_resif); @@ -676,8 +685,8 @@ read_acl_interface_tag_actions(struct acl_list* acl_interface, return 0; } for(i = 0; istr, - p->str2, p->str3, 1, port)) { + if(!acl_list_tag_action_cfg(acl_interface, cfg, + resif[i], p->str2, p->str3, 1, port)) { config_deltrplstrlist(p); config_del_strarray(resif, num_resif); return 0; @@ -714,8 +723,8 @@ read_acl_interface_tag_datas(struct acl_list* acl_interface, return 0; } for(i = 0; istr, - p->str2, p->str3, 1, port)) { + if(!acl_list_tag_data_cfg(acl_interface, cfg, + resif[i], p->str2, p->str3, 1, port)) { config_deltrplstrlist(p); config_del_strarray(resif, num_resif); return 0; diff --git a/daemon/acl_list.h b/daemon/acl_list.h index 6617ec8c4..930f978d3 100644 --- a/daemon/acl_list.h +++ b/daemon/acl_list.h @@ -123,14 +123,15 @@ void acl_list_delete(struct acl_list* acl); * Insert interface in the alc_list. This should happen when the listening * interface is setup. * @param acl_interface: acl_list to insert to. - * @param interface: interface (IP) in string format. - * @param s2: acl_access in string format. - * @param port: default port. + * @param addr: interface IP. + * @param addrlen: length of the interface IP. + * @param control: acl_access. * @return new structure or NULL on error. */ struct acl_addr* -acl_interface_insert(struct acl_list* acl_interface, const char* interface, - const char* s2, int port); +acl_interface_insert(struct acl_list* acl_interface, + struct sockaddr_storage* addr, socklen_t addrlen, + enum acl_access control); /** * Process access control config. diff --git a/daemon/daemon.c b/daemon/daemon.c index 28a06175d..71091133a 100644 --- a/daemon/daemon.c +++ b/daemon/daemon.c @@ -96,6 +96,9 @@ #ifdef HAVE_SYSTEMD #include #endif +#ifdef HAVE_NETDB_H +#include +#endif /** How many quit requests happened. */ static int sig_record_quit = 0; @@ -314,6 +317,29 @@ daemon_init(void) return daemon; } +static int setup_acl_for_ports(struct acl_list* list, + struct listen_port* port_list) +{ + struct acl_addr* acl_node; + struct addrinfo* addr; + for(; port_list; port_list=port_list->next) { + if(!port_list->socket) { + /* This is mainly for testbound where port_list is + * empty. */ + continue; + } + addr = port_list->socket->addr; + if(!(acl_node = acl_interface_insert(list, + (struct sockaddr_storage*)addr->ai_addr, + (socklen_t)addr->ai_addrlen, + acl_refuse))) { + return 0; + } + port_list->socket->acl = acl_node; + } + return 1; +} + int daemon_open_shared_ports(struct daemon* daemon) { @@ -342,8 +368,8 @@ daemon_open_shared_ports(struct daemon* daemon) daemon->reuseport = 1; #endif /* try to use reuseport */ - p0 = listening_ports_open(daemon->cfg, daemon->acl_interface, - resif, num_resif, &daemon->reuseport); + p0 = listening_ports_open(daemon->cfg, resif, num_resif, + &daemon->reuseport); if(!p0) { listening_ports_free(p0); config_del_strarray(resif, num_resif); @@ -364,12 +390,17 @@ daemon_open_shared_ports(struct daemon* daemon) return 0; } daemon->ports[0] = p0; + if(!setup_acl_for_ports(daemon->acl_interface, + daemon->ports[0])) { + listening_ports_free(p0); + config_del_strarray(resif, num_resif); + return 0; + } if(daemon->reuseport) { /* continue to use reuseport */ for(i=1; inum_ports; i++) { if(!(daemon->ports[i]= listening_ports_open(daemon->cfg, - daemon->acl_interface, resif, num_resif, &daemon->reuseport)) || !daemon->reuseport ) { @@ -380,6 +411,15 @@ daemon_open_shared_ports(struct daemon* daemon) config_del_strarray(resif, num_resif); return 0; } + if(!setup_acl_for_ports(daemon->acl_interface, + daemon->ports[i])) { + for(i=0; inum_ports; i++) + listening_ports_free(daemon->ports[i]); + free(daemon->ports); + daemon->ports = NULL; + config_del_strarray(resif, num_resif); + return 0; + } } } config_del_strarray(resif, num_resif); diff --git a/services/listen_dnsport.c b/services/listen_dnsport.c index fb2c53ba2..e823b3c12 100644 --- a/services/listen_dnsport.c +++ b/services/listen_dnsport.c @@ -1196,7 +1196,6 @@ if_is_ssl(const char* ifname, const char* port, int ssl_port, * @param hints: for getaddrinfo. family and flags have to be set by caller. * @param port: Port number to use (as string). * @param list: list of open ports, appended to, changed to point to list head. - * @param acl_interface: acl list with options for the interface. * @param rcv: receive buffer size for UDP * @param snd: send buffer size for UDP * @param ssl_port: ssl service port number @@ -1216,7 +1215,7 @@ if_is_ssl(const char* ifname, const char* port, int ssl_port, static int ports_create_if(const char* ifname, int do_auto, int do_udp, int do_tcp, struct addrinfo *hints, const char* port, struct listen_port** list, - struct acl_list* acl_interface, size_t rcv, size_t snd, int ssl_port, + size_t rcv, size_t snd, int ssl_port, struct config_strlist* tls_additional_port, int https_port, int* reuseport, int transparent, int tcp_mss, int freebind, int http2_nodelay, int use_systemd, int dnscrypt_port, int dscp) @@ -1225,7 +1224,6 @@ ports_create_if(const char* ifname, int do_auto, int do_udp, int do_tcp, int is_https = if_is_https(ifname, port, https_port); int nodelay = is_https && http2_nodelay; struct unbound_socket* ub_sock; - struct acl_addr* acl_node; #ifdef USE_DNSCRYPT int is_dnscrypt = ((strchr(ifname, '@') && atoi(strchr(ifname, '@')+1) == dnscrypt_port) || @@ -1240,7 +1238,6 @@ ports_create_if(const char* ifname, int do_auto, int do_udp, int do_tcp, if(do_auto) { ub_sock = calloc(1, sizeof(struct unbound_socket)); - acl_node = NULL; if(!ub_sock) return 0; if((s = make_sock_port(SOCK_DGRAM, ifname, port, hints, 1, @@ -1269,17 +1266,8 @@ ports_create_if(const char* ifname, int do_auto, int do_udp, int do_tcp, free(ub_sock); return 0; } - if(!(acl_node = acl_interface_insert(acl_interface, ifname, - "refuse", ntohs(((struct sockaddr_in*)ub_sock->addr->ai_addr)->sin_port)))) { - sock_close(s); - freeaddrinfo(ub_sock->addr); - free(ub_sock); - return 0; - } - ub_sock->acl = acl_node; } else if(do_udp) { ub_sock = calloc(1, sizeof(struct unbound_socket)); - acl_node = NULL; if(!ub_sock) return 0; /* regular udp socket */ @@ -1301,21 +1289,12 @@ ports_create_if(const char* ifname, int do_auto, int do_udp, int do_tcp, free(ub_sock); return 0; } - if(!(acl_node = acl_interface_insert(acl_interface, ifname, - "refuse", ntohs(((struct sockaddr_in*)ub_sock->addr->ai_addr)->sin_port)))) { - sock_close(s); - freeaddrinfo(ub_sock->addr); - free(ub_sock); - return 0; - } - ub_sock->acl = acl_node; } if(do_tcp) { int is_ssl = if_is_ssl(ifname, port, ssl_port, tls_additional_port); enum listen_type port_type; ub_sock = calloc(1, sizeof(struct unbound_socket)); - acl_node = NULL; if(!ub_sock) return 0; if(is_ssl) @@ -1345,14 +1324,6 @@ ports_create_if(const char* ifname, int do_auto, int do_udp, int do_tcp, free(ub_sock); return 0; } - if(!(acl_node = acl_interface_insert(acl_interface, ifname, - "refuse", ntohs(((struct sockaddr_in*)ub_sock->addr->ai_addr)->sin_port)))) { - sock_close(s); - freeaddrinfo(ub_sock->addr); - free(ub_sock); - return 0; - } - ub_sock->acl = acl_node; } return 1; } @@ -1750,8 +1721,8 @@ int resolve_interface_names(char** ifs, int num_ifs, } struct listen_port* -listening_ports_open(struct config_file* cfg, struct acl_list* acl_interface, - char** ifs, int num_ifs, int* reuseport) +listening_ports_open(struct config_file* cfg, char** ifs, int num_ifs, + int* reuseport) { struct listen_port* list = NULL; struct addrinfo hints; @@ -1842,7 +1813,7 @@ listening_ports_open(struct config_file* cfg, struct acl_list* acl_interface, hints.ai_family = AF_INET6; if(!ports_create_if(do_auto?"::0":"::1", do_auto, cfg->do_udp, do_tcp, - &hints, portbuf, &list, acl_interface, + &hints, portbuf, &list, cfg->so_rcvbuf, cfg->so_sndbuf, cfg->ssl_port, cfg->tls_additional_port, cfg->https_port, reuseport, cfg->ip_transparent, @@ -1857,7 +1828,7 @@ listening_ports_open(struct config_file* cfg, struct acl_list* acl_interface, hints.ai_family = AF_INET; if(!ports_create_if(do_auto?"0.0.0.0":"127.0.0.1", do_auto, cfg->do_udp, do_tcp, - &hints, portbuf, &list, acl_interface, + &hints, portbuf, &list, cfg->so_rcvbuf, cfg->so_sndbuf, cfg->ssl_port, cfg->tls_additional_port, cfg->https_port, reuseport, cfg->ip_transparent, @@ -1874,7 +1845,7 @@ listening_ports_open(struct config_file* cfg, struct acl_list* acl_interface, continue; hints.ai_family = AF_INET6; if(!ports_create_if(ifs[i], 0, cfg->do_udp, - do_tcp, &hints, portbuf, &list, acl_interface, + do_tcp, &hints, portbuf, &list, cfg->so_rcvbuf, cfg->so_sndbuf, cfg->ssl_port, cfg->tls_additional_port, cfg->https_port, reuseport, cfg->ip_transparent, @@ -1889,7 +1860,7 @@ listening_ports_open(struct config_file* cfg, struct acl_list* acl_interface, continue; hints.ai_family = AF_INET; if(!ports_create_if(ifs[i], 0, cfg->do_udp, - do_tcp, &hints, portbuf, &list, acl_interface, + do_tcp, &hints, portbuf, &list, cfg->so_rcvbuf, cfg->so_sndbuf, cfg->ssl_port, cfg->tls_additional_port, cfg->https_port, reuseport, cfg->ip_transparent, diff --git a/services/listen_dnsport.h b/services/listen_dnsport.h index 70b3da0f0..f27fa597b 100644 --- a/services/listen_dnsport.h +++ b/services/listen_dnsport.h @@ -138,7 +138,6 @@ struct listen_port { * interfaces for IP4 and/or IP6, for UDP and/or TCP. * On the given port number. It creates the sockets. * @param cfg: settings on what ports to open. - * @param acl_interface: acl list for interface options. * @param ifs: interfaces to open, array of IP addresses, "ip[@port]". * @param num_ifs: length of ifs. * @param reuseport: set to true if you want reuseport, or NULL to not have it, @@ -147,7 +146,6 @@ struct listen_port { * @return: linked list of ports or NULL on error. */ struct listen_port* listening_ports_open(struct config_file* cfg, - struct acl_list* acl_interface, char** ifs, int num_ifs, int* reuseport); /** diff --git a/testcode/fake_event.c b/testcode/fake_event.c index a50e2f3b1..03e1c04f3 100644 --- a/testcode/fake_event.c +++ b/testcode/fake_event.c @@ -1341,11 +1341,10 @@ int resolve_interface_names(char** ATTR_UNUSED(ifs), int ATTR_UNUSED(num_ifs), } struct listen_port* listening_ports_open(struct config_file* ATTR_UNUSED(cfg), - struct acl_list* ATTR_UNUSED(acl_interface), char** ATTR_UNUSED(ifs), int ATTR_UNUSED(num_ifs), int* ATTR_UNUSED(reuseport)) { - return calloc(1, 1); + return calloc(1, sizeof(struct listen_port)); } void listening_ports_free(struct listen_port* list) diff --git a/testdata/acl_interface.tdir/acl_interface.conf b/testdata/acl_interface.tdir/acl_interface.conf index 0c2314770..157a2d7b7 100644 --- a/testdata/acl_interface.tdir/acl_interface.conf +++ b/testdata/acl_interface.tdir/acl_interface.conf @@ -6,22 +6,39 @@ server: chroot: "" username: "" do-not-query-localhost: no - use-caps-for-id: yes + use-caps-for-id: no + define-tag: "one two refuse" # Interface configuration for IPv4 interface: @IPV4_ADDR@@@PORT_ALLOW@ interface: @IPV4_ADDR@@@PORT_DENY@ interface: @IPV4_ADDR@@@PORT_REFUSE@ + interface: @IPV4_ADDR@@@PORT_TAG_1@ + interface: @IPV4_ADDR@@@PORT_TAG_2@ + interface: @IPV4_ADDR@@@PORT_TAG_3@ interface: @IPV4_ADDR@@@PORT_VIEW_INT@ interface: @IPV4_ADDR@@@PORT_VIEW_EXT@ interface: @IPV4_ADDR@@@PORT_VIEW_INTEXT@ interface-action: @IPV4_ADDR@@@PORT_ALLOW@ allow interface-action: @IPV4_ADDR@@@PORT_DENY@ deny + # interface-action: @IPV4_ADDR@@@PORT_REFUSE@ refuse # This is the default action + interface-action: @IPV4_ADDR@@@PORT_TAG_1@ allow + interface-action: @IPV4_ADDR@@@PORT_TAG_2@ allow + interface-action: @IPV4_ADDR@@@PORT_TAG_3@ allow interface-action: @IPV4_ADDR@@@PORT_VIEW_INT@ allow interface-action: @IPV4_ADDR@@@PORT_VIEW_EXT@ allow interface-action: @IPV4_ADDR@@@PORT_VIEW_INTEXT@ allow + interface-tag: @IPV4_ADDR@@@PORT_TAG_1@ "one" + interface-tag: @IPV4_ADDR@@@PORT_TAG_2@ "two" + interface-tag: @IPV4_ADDR@@@PORT_TAG_3@ "refuse" + interface-tag-action: @IPV4_ADDR@@@PORT_TAG_1@ one redirect + interface-tag-data: @IPV4_ADDR@@@PORT_TAG_1@ one "A 1.1.1.1" + interface-tag-action: @IPV4_ADDR@@@PORT_TAG_2@ two redirect + interface-tag-data: @IPV4_ADDR@@@PORT_TAG_2@ two "A 2.2.2.2" + interface-tag-action: @IPV4_ADDR@@@PORT_TAG_3@ refuse always_refuse + interface-view: @IPV4_ADDR@@@PORT_VIEW_INT@ "int" interface-view: @IPV4_ADDR@@@PORT_VIEW_EXT@ "ext" interface-view: @IPV4_ADDR@@@PORT_VIEW_INTEXT@ "intext" @@ -30,20 +47,75 @@ server: interface: @IPV6_ADDR@@@PORT_ALLOW@ interface: @IPV6_ADDR@@@PORT_DENY@ interface: @IPV6_ADDR@@@PORT_REFUSE@ + interface: @IPV6_ADDR@@@PORT_TAG_1@ + interface: @IPV6_ADDR@@@PORT_TAG_2@ + interface: @IPV6_ADDR@@@PORT_TAG_3@ interface: @IPV6_ADDR@@@PORT_VIEW_INT@ interface: @IPV6_ADDR@@@PORT_VIEW_EXT@ interface: @IPV6_ADDR@@@PORT_VIEW_INTEXT@ interface-action: @IPV6_ADDR@@@PORT_ALLOW@ allow interface-action: @IPV6_ADDR@@@PORT_DENY@ deny + # interface-action: @IPV6_ADDR@@@PORT_REFUSE@ refuse # This is the default action + interface-action: @IPV6_ADDR@@@PORT_TAG_1@ allow + interface-action: @IPV6_ADDR@@@PORT_TAG_2@ allow + interface-action: @IPV6_ADDR@@@PORT_TAG_3@ allow interface-action: @IPV6_ADDR@@@PORT_VIEW_INT@ allow interface-action: @IPV6_ADDR@@@PORT_VIEW_EXT@ allow interface-action: @IPV6_ADDR@@@PORT_VIEW_INTEXT@ allow + interface-tag: @IPV6_ADDR@@@PORT_TAG_1@ "one" + interface-tag: @IPV6_ADDR@@@PORT_TAG_2@ "two" + interface-tag: @IPV6_ADDR@@@PORT_TAG_3@ "refuse" + interface-tag-action: @IPV6_ADDR@@@PORT_TAG_1@ one redirect + interface-tag-data: @IPV6_ADDR@@@PORT_TAG_1@ one "A 1.1.1.1" + interface-tag-action: @IPV6_ADDR@@@PORT_TAG_2@ two redirect + interface-tag-data: @IPV6_ADDR@@@PORT_TAG_2@ two "A 2.2.2.2" + interface-tag-action: @IPV6_ADDR@@@PORT_TAG_3@ refuse always_refuse + interface-view: @IPV6_ADDR@@@PORT_VIEW_INT@ "int" interface-view: @IPV6_ADDR@@@PORT_VIEW_EXT@ "ext" interface-view: @IPV6_ADDR@@@PORT_VIEW_INTEXT@ "intext" +# Mirrored interface configuration for interface name + interface: @INTERFACE@@@PORT_ALLOW@ + interface: @INTERFACE@@@PORT_DENY@ + interface: @INTERFACE@@@PORT_REFUSE@ + interface: @INTERFACE@@@PORT_TAG_1@ + interface: @INTERFACE@@@PORT_TAG_2@ + interface: @INTERFACE@@@PORT_TAG_3@ + interface: @INTERFACE@@@PORT_VIEW_INT@ + interface: @INTERFACE@@@PORT_VIEW_EXT@ + interface: @INTERFACE@@@PORT_VIEW_INTEXT@ + + interface-action: @INTERFACE@@@PORT_ALLOW@ allow + interface-action: @INTERFACE@@@PORT_DENY@ deny + # interface-action: @INTERFACE@@@PORT_REFUSE@ refuse # This is the default action + interface-action: @INTERFACE@@@PORT_TAG_1@ allow + interface-action: @INTERFACE@@@PORT_TAG_2@ allow + interface-action: @INTERFACE@@@PORT_TAG_3@ allow + interface-action: @INTERFACE@@@PORT_VIEW_INT@ allow + interface-action: @INTERFACE@@@PORT_VIEW_EXT@ allow + interface-action: @INTERFACE@@@PORT_VIEW_INTEXT@ allow + + interface-tag: @INTERFACE@@@PORT_TAG_1@ "one" + interface-tag: @INTERFACE@@@PORT_TAG_2@ "two" + interface-tag: @INTERFACE@@@PORT_TAG_3@ "refuse" + interface-tag-action: @INTERFACE@@@PORT_TAG_1@ one redirect + interface-tag-data: @INTERFACE@@@PORT_TAG_1@ one "A 1.1.1.1" + interface-tag-action: @INTERFACE@@@PORT_TAG_2@ two redirect + interface-tag-data: @INTERFACE@@@PORT_TAG_2@ two "A 2.2.2.2" + interface-tag-action: @INTERFACE@@@PORT_TAG_3@ refuse always_refuse + + interface-view: @INTERFACE@@@PORT_VIEW_INT@ "int" + interface-view: @INTERFACE@@@PORT_VIEW_EXT@ "ext" + interface-view: @INTERFACE@@@PORT_VIEW_INTEXT@ "intext" + +# Local zones configuration + local-zone: local. transparent + local-data: "local. A 0.0.0.0" + local-zone-tag: local. "one two refuse" + # Views configuration view: name: "int" diff --git a/testdata/acl_interface.tdir/acl_interface.pre b/testdata/acl_interface.tdir/acl_interface.pre index 14f2fb599..ce5358c1b 100644 --- a/testdata/acl_interface.tdir/acl_interface.pre +++ b/testdata/acl_interface.tdir/acl_interface.pre @@ -7,25 +7,37 @@ if test ! -x "`which unshare 2>&1`"; then skip_test "no unshare (from util-linux package) available, skip test" fi -get_random_port 8 +get_random_port 11 PORT_ALLOW=$RND_PORT PORT_DENY=$(($RND_PORT + 1)) PORT_REFUSE=$(($RND_PORT + 2)) -PORT_VIEW_INT=$(($RND_PORT + 3)) -PORT_VIEW_EXT=$(($RND_PORT + 4)) -PORT_VIEW_INTEXT=$(($RND_PORT + 5)) -FORWARD_PORT=$(($RND_PORT + 6)) -STUB_PORT=$(($RND_PORT + 7)) +PORT_TAG_1=$(($RND_PORT + 3)) +PORT_TAG_2=$(($RND_PORT + 4)) +PORT_TAG_3=$(($RND_PORT + 5)) +PORT_VIEW_INT=$(($RND_PORT + 6)) +PORT_VIEW_EXT=$(($RND_PORT + 7)) +PORT_VIEW_INTEXT=$(($RND_PORT + 8)) +FORWARD_PORT=$(($RND_PORT + 9)) +STUB_PORT=$(($RND_PORT + 10)) IPV4_ADDR=192.168.1.1 IPV6_ADDR=2001:db8::1 +INTERFACE=eth24 +INTERFACE_ADDR_1=10.0.0.1 +INTERFACE_ADDR_2=10.0.0.2 +INTERFACE_ADDR_3=10.0.0.3 +INTERFACE_ADDR_4=10.0.0.4 + # make config file sed \ -e 's/@PORT_ALLOW\@/'$PORT_ALLOW'/' \ -e 's/@PORT_DENY\@/'$PORT_DENY'/' \ -e 's/@PORT_REFUSE\@/'$PORT_REFUSE'/' \ + -e 's/@PORT_TAG_1\@/'$PORT_TAG_1'/' \ + -e 's/@PORT_TAG_2\@/'$PORT_TAG_2'/' \ + -e 's/@PORT_TAG_3\@/'$PORT_TAG_3'/' \ -e 's/@PORT_VIEW_INT\@/'$PORT_VIEW_INT'/' \ -e 's/@PORT_VIEW_EXT\@/'$PORT_VIEW_EXT'/' \ -e 's/@PORT_VIEW_INTEXT\@/'$PORT_VIEW_INTEXT'/' \ @@ -33,6 +45,7 @@ sed \ -e 's/@STUB_PORT\@/'$STUB_PORT'/' \ -e 's/@IPV4_ADDR\@/'$IPV4_ADDR'/' \ -e 's/@IPV6_ADDR\@/'$IPV6_ADDR'/' \ + -e 's/@INTERFACE\@/'$INTERFACE'/' \ < acl_interface.conf > ub.conf if test -x "`which bash`"; then @@ -44,6 +57,9 @@ fi echo "PORT_ALLOW=$PORT_ALLOW" >> .tpkg.var.test echo "PORT_DENY=$PORT_DENY" >> .tpkg.var.test echo "PORT_REFUSE=$PORT_REFUSE" >> .tpkg.var.test +echo "PORT_TAG_1=$PORT_TAG_1" >> .tpkg.var.test +echo "PORT_TAG_2=$PORT_TAG_2" >> .tpkg.var.test +echo "PORT_TAG_3=$PORT_TAG_3" >> .tpkg.var.test echo "PORT_VIEW_INT=$PORT_VIEW_INT" >> .tpkg.var.test echo "PORT_VIEW_EXT=$PORT_VIEW_EXT" >> .tpkg.var.test echo "PORT_VIEW_INTEXT=$PORT_VIEW_INTEXT" >> .tpkg.var.test @@ -51,4 +67,9 @@ echo "FORWARD_PORT=$FORWARD_PORT" >> .tpkg.var.test echo "STUB_PORT=$STUB_PORT" >> .tpkg.var.test echo "IPV4_ADDR=$IPV4_ADDR" >> .tpkg.var.test echo "IPV6_ADDR=$IPV6_ADDR" >> .tpkg.var.test +echo "INTERFACE=$INTERFACE" >> .tpkg.var.test +echo "INTERFACE_ADDR_1=$INTERFACE_ADDR_1" >> .tpkg.var.test +echo "INTERFACE_ADDR_2=$INTERFACE_ADDR_2" >> .tpkg.var.test +echo "INTERFACE_ADDR_3=$INTERFACE_ADDR_3" >> .tpkg.var.test +echo "INTERFACE_ADDR_4=$INTERFACE_ADDR_4" >> .tpkg.var.test echo "shell=$shell" >> .tpkg.var.test diff --git a/testdata/acl_interface.tdir/acl_interface.test.scenario b/testdata/acl_interface.tdir/acl_interface.test.scenario index d30c64d3f..00b2b059f 100644 --- a/testdata/acl_interface.tdir/acl_interface.test.scenario +++ b/testdata/acl_interface.tdir/acl_interface.test.scenario @@ -10,6 +10,13 @@ ip addr add $IPV4_ADDR dev lo ip addr add $IPV6_ADDR dev lo ip link set lo up +ip link add $INTERFACE type dummy +ip addr add $INTERFACE_ADDR_1 dev $INTERFACE +ip addr add $INTERFACE_ADDR_2 dev $INTERFACE +ip addr add $INTERFACE_ADDR_3 dev $INTERFACE +ip addr add $INTERFACE_ADDR_4 dev $INTERFACE +ip link set $INTERFACE up + # start the forwarder in the background get_ldns_testns $LDNS_TESTNS -p $FORWARD_PORT acl_interface.testns >fwd.log 2>&1 & @@ -31,6 +38,14 @@ wait_ldns_testns_up fwd.log wait_ldns_testns_up fwd2.log wait_unbound_up unbound.log +end () { + echo "> cat logfiles" + cat fwd.log + cat fwd2.log + cat unbound.log + exit $1 +} + # Query for the given domain to the given port # $1: address family [4, 6] # $2: port @@ -44,13 +59,22 @@ query () { dig @"$addr" -p $2 $3 | tee outfile } +# Query for the given domain to the given port +# $1: address +# $2: port +# $3: dname +query_addr () { + echo "> dig @$1 -p $2 $3" + dig @"$1" -p $2 $3 | tee outfile +} + expect_refused () { echo "> check answer for REFUSED" if grep "REFUSED" outfile; then echo "OK" else echo "Not OK" - exit 1 + end 1 fi } @@ -60,7 +84,7 @@ expect_external_answer () { echo "OK" else echo "Not OK" - exit 1 + end 1 fi } @@ -70,10 +94,29 @@ expect_internal_answer () { echo "OK" else echo "Not OK" - exit 1 + end 1 + fi +} + +expect_tag_one_answer () { + echo "> check tag 'one' answer" + if grep "1.1.1.1" outfile; then + echo "OK" + else + echo "Not OK" + end 1 fi } +expect_tag_two_answer () { + echo "> check tag 'two' answer" + if grep "2.2.2.2" outfile; then + echo "OK" + else + echo "Not OK" + end 1 + fi +} # do the test @@ -90,6 +133,15 @@ for i in 4 6; do query $i $PORT_ALLOW "www.internal" expect_internal_answer + query $i $PORT_TAG_1 "local" + expect_tag_one_answer + + query $i $PORT_TAG_2 "local" + expect_tag_two_answer + + query $i $PORT_TAG_3 "local" + expect_refused + query $i $PORT_VIEW_INT "www.internal" expect_internal_answer @@ -109,8 +161,45 @@ for i in 4 6; do expect_external_answer done -echo "> cat logfiles" -cat fwd.log -cat fwd2.log -cat unbound.log -exit 0 +for addr in $INTERFACE_ADDR_1 $INTERFACE_ADDR_2 $INTERFACE_ADDR_3 $INTERFACE_ADDR_4; do + query_addr $addr $PORT_REFUSE "www.external" + expect_refused + + query_addr $addr $PORT_REFUSE "www.internal" + expect_refused + + query_addr $addr $PORT_ALLOW "www.external" + expect_external_answer + + query_addr $addr $PORT_ALLOW "www.internal" + expect_internal_answer + + query_addr $addr $PORT_TAG_1 "local" + expect_tag_one_answer + + query_addr $addr $PORT_TAG_2 "local" + expect_tag_two_answer + + query_addr $addr $PORT_TAG_3 "local" + expect_refused + + query_addr $addr $PORT_VIEW_INT "www.internal" + expect_internal_answer + + query_addr $addr $PORT_VIEW_INT "www.external" + expect_refused + + query_addr $addr $PORT_VIEW_EXT "www.internal" + expect_refused + + query_addr $addr $PORT_VIEW_EXT "www.external" + expect_external_answer + + query_addr $addr $PORT_VIEW_INTEXT "www.internal" + expect_internal_answer + + query_addr $addr $PORT_VIEW_INTEXT "www.external" + expect_external_answer +done + +end 0 diff --git a/testdata/acl_interface.tdir/acl_interface.testns b/testdata/acl_interface.tdir/acl_interface.testns index 62abf6928..d8c871b1c 100644 --- a/testdata/acl_interface.tdir/acl_interface.testns +++ b/testdata/acl_interface.tdir/acl_interface.testns @@ -11,3 +11,16 @@ www IN A SECTION ANSWER www IN A 1.2.3.4 ENTRY_END + +$ORIGIN local. +$TTL 3600 + +ENTRY_BEGIN +MATCH opcode qtype qname +REPLY QR AA NOERROR +ADJUST copy_id +SECTION QUESTION +@ IN A +SECTION ANSWER +@ IN A 127.0.0.1 +ENTRY_END diff --git a/util/fptr_wlist.c b/util/fptr_wlist.c index 750f45b50..dc8ab6693 100644 --- a/util/fptr_wlist.c +++ b/util/fptr_wlist.c @@ -44,7 +44,6 @@ * boundaries in the program. */ #include "config.h" -#include "daemon/acl_list.h" #include "util/fptr_wlist.h" #include "util/mini_event.h" #include "services/outside_network.h" @@ -222,6 +221,7 @@ fptr_whitelist_rbtree_cmp(int (*fptr) (const void *, const void *)) if(fptr == &mesh_state_compare) return 1; else if(fptr == &mesh_state_ref_compare) return 1; else if(fptr == &addr_tree_compare) return 1; + else if(fptr == &addr_tree_addrport_compare) return 1; else if(fptr == &local_zone_cmp) return 1; else if(fptr == &local_data_cmp) return 1; else if(fptr == &fwd_cmp) return 1; @@ -245,7 +245,6 @@ fptr_whitelist_rbtree_cmp(int (*fptr) (const void *, const void *)) else if(fptr == &auth_zone_cmp) return 1; else if(fptr == &auth_data_cmp) return 1; else if(fptr == &auth_xfer_cmp) return 1; - else if(fptr == &acl_interface_compare) return 1; return 0; } diff --git a/util/storage/dnstree.c b/util/storage/dnstree.c index f883044af..eef393f91 100644 --- a/util/storage/dnstree.c +++ b/util/storage/dnstree.c @@ -71,6 +71,14 @@ int addr_tree_compare(const void* k1, const void* k2) return 0; } +int addr_tree_addrport_compare(const void* k1, const void* k2) +{ + struct addr_tree_node* n1 = (struct addr_tree_node*)k1; + struct addr_tree_node* n2 = (struct addr_tree_node*)k2; + return sockaddr_cmp(&n1->addr, n1->addrlen, &n2->addr, + n2->addrlen); +} + void name_tree_init(rbtree_type* tree) { rbtree_init(tree, &name_tree_compare); @@ -81,6 +89,11 @@ void addr_tree_init(rbtree_type* tree) rbtree_init(tree, &addr_tree_compare); } +void addr_tree_addrport_init(rbtree_type* tree) +{ + rbtree_init(tree, &addr_tree_addrport_compare); +} + int name_tree_insert(rbtree_type* tree, struct name_tree_node* node, uint8_t* name, size_t len, int labs, uint16_t dclass) { diff --git a/util/storage/dnstree.h b/util/storage/dnstree.h index d54602fd7..8aaa94098 100644 --- a/util/storage/dnstree.h +++ b/util/storage/dnstree.h @@ -153,6 +153,13 @@ int name_tree_next_root(rbtree_type* tree, uint16_t* dclass); */ void addr_tree_init(rbtree_type* tree); +/** + * Init addr tree to be empty. + * The comparison function to be used is addr_tree_addrport_compare. + * @param tree: to init. + */ +void addr_tree_addrport_init(rbtree_type* tree); + /** * insert element into addr tree. * @param tree: addr tree @@ -207,4 +214,7 @@ int name_tree_compare(const void* k1, const void* k2); /** compare addr tree nodes */ int addr_tree_compare(const void* k1, const void* k2); +/** compare addr tree nodes (address and port only) */ +int addr_tree_addrport_compare(const void* k1, const void* k2); + #endif /* UTIL_STORAGE_DNSTREE_H */