From patchwork Tue Sep 7 18:53:59 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Bauer X-Patchwork-Id: 1525483 X-Patchwork-Delegate: mail@david-bauer.net Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; secure) header.d=lists.infradead.org header.i=@lists.infradead.org header.a=rsa-sha256 header.s=bombadil.20210309 header.b=3OH4C740; dkim-atps=neutral Authentication-Results: ozlabs.org; spf=none (no SPF record) smtp.mailfrom=lists.openwrt.org (client-ip=2607:7c80:54:e::133; helo=bombadil.infradead.org; envelope-from=openwrt-devel-bounces+incoming=patchwork.ozlabs.org@lists.openwrt.org; receiver=) Received: from bombadil.infradead.org (bombadil.infradead.org [IPv6:2607:7c80:54:e::133]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 4H3vf94p2yz9sXk for ; Wed, 8 Sep 2021 04:57:37 +1000 (AEST) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:Message-Id:Date:Subject:Cc :To:From:Reply-To:Content-ID:Content-Description:Resent-Date:Resent-From: Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:In-Reply-To:References: List-Owner; bh=fTD1f4gHw8M+YbD4vV5yPjS9Alb/UQAJzsUPsyy8h2A=; b=3OH4C740dir5TL BYj5zw8VE2mMrWOz5IakoL6IxUyeHvTAQTz3e/fjDkhYhYd2cTivGn8zaNyXMEv4PPuJd0wXeZ/5n ocWuJqFw2BvnLGl0XPfkawGP8dxYK+EBzx+ZGWKGcHRWZVd0RLmRaaSGiIuCmDPiGsaMJBD0ncrjj LwzBOhAKxMX3frt5SL+7HUVpNpIrh3dBBr3vE6pjHeQa/ByZ48FW8uE8QQcdPql5yJKW1l/g2Qo8b LTBV+FFNJItiovGeh2REeWOafdiAiUcMOJIvqjOWh/km/daYWQoVDHIvcLJeWQ2zq+fYwkytsc8n8 sDwZ8rwOYvO4dpfV0o5Q==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1mNgFA-004Trt-KN; Tue, 07 Sep 2021 18:54:52 +0000 Received: from perseus.uberspace.de ([95.143.172.134]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1mNgF5-004Tqg-3L for openwrt-devel@lists.openwrt.org; Tue, 07 Sep 2021 18:54:50 +0000 Received: (qmail 27728 invoked from network); 7 Sep 2021 18:54:36 -0000 Received: from localhost (HELO localhost) (127.0.0.1) by perseus.uberspace.de with SMTP; 7 Sep 2021 18:54:36 -0000 From: David Bauer To: nbd@nbd.name, john@phrozen.org, openwrt-devel@lists.openwrt.org Cc: Jan Braun Subject: [PATCH usteer] usteer: add support for IPv6 remote exchange Date: Tue, 7 Sep 2021 20:53:59 +0200 Message-Id: <20210907185359.27018-1-mail@david-bauer.net> X-Mailer: git-send-email 2.33.0 MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20210907_115447_491198_123AA50E X-CRM114-Status: GOOD ( 20.99 ) X-Spam-Score: -0.7 (/) X-Spam-Report: Spam detection software, running on the system "bombadil.infradead.org", has NOT identified this incoming email as spam. The original message has been attached to this so you can view it or label similar future email. If you have any questions, see the administrator of that system for details. Content preview: From: Jan Braun This adds optional support for message exchange using IPv6 multicast messaging. This has the ability for routers and switches between nodes to route traffic between usteer nodes multicast-aware. Content analysis details: (-0.7 points, 5.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- -0.7 RCVD_IN_DNSWL_LOW RBL: Sender listed at https://www.dnswl.org/, low trust [95.143.172.134 listed in list.dnswl.org] -0.0 SPF_PASS SPF: sender matches SPF record 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record X-BeenThere: openwrt-devel@lists.openwrt.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: OpenWrt Development List List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "openwrt-devel" Errors-To: openwrt-devel-bounces+incoming=patchwork.ozlabs.org@lists.openwrt.org From: Jan Braun This adds optional support for message exchange using IPv6 multicast messaging. This has the ability for routers and switches between nodes to route traffic between usteer nodes multicast-aware. By default, IPv4 is used. IPv6 can be enabled by configuring the ipv6 option to 1. Signed-off-by: Jan Braun [squash commits - adapt usock usage] Signed-off-by: David Bauer --- main.c | 1 - openwrt/usteer/files/etc/config/usteer | 3 + openwrt/usteer/files/etc/init.d/usteer | 1 + remote.c | 172 ++++++++++++++++++++++--- ubus.c | 3 + usteer.h | 5 + 6 files changed, 166 insertions(+), 19 deletions(-) diff --git a/main.c b/main.c index ad53af8..9d01419 100644 --- a/main.c +++ b/main.c @@ -204,7 +204,6 @@ int main(int argc, char **argv) } ubus_add_uloop(ubus_ctx); - usteer_interface_init(); if (dump_time) { dump_timer.cb = usteer_dump_timeout; uloop_timeout_set(&dump_timer, dump_time * 1000); diff --git a/openwrt/usteer/files/etc/config/usteer b/openwrt/usteer/files/etc/config/usteer index 5e30ccf..3ba1c6d 100644 --- a/openwrt/usteer/files/etc/config/usteer +++ b/openwrt/usteer/files/etc/config/usteer @@ -5,6 +5,9 @@ config usteer # Log messages to syslog (0/1) option 'syslog' '1' + # Use IPv6 for remote exchange + option 'ipv6' '0' + # Minimum level of logged messages # 0 = fatal # 1 = info diff --git a/openwrt/usteer/files/etc/init.d/usteer b/openwrt/usteer/files/etc/init.d/usteer index 9289557..15add88 100755 --- a/openwrt/usteer/files/etc/init.d/usteer +++ b/openwrt/usteer/files/etc/init.d/usteer @@ -65,6 +65,7 @@ uci_usteer() { local cfg="$1" uci_option_to_json_bool "$cfg" syslog + uci_option_to_json_bool "$cfg" ipv6 uci_option_to_json_bool "$cfg" load_kick_enabled uci_option_to_json_bool "$cfg" assoc_steering uci_option_to_json_string "$cfg" node_up_script diff --git a/remote.c b/remote.c index 16ecb0f..dd95ece 100644 --- a/remote.c +++ b/remote.c @@ -277,10 +277,9 @@ interface_add_node(struct usteer_remote_host *host, struct blob_attr *data) } static void -interface_recv_msg(struct interface *iface, struct in_addr *addr, void *buf, int len) +interface_recv_msg(struct interface *iface, char *addr_str, void *buf, int len) { struct usteer_remote_host *host; - char addr_str[INET_ADDRSTRLEN]; struct blob_attr *data = buf; struct apmsg msg; struct blob_attr *cur; @@ -302,8 +301,6 @@ interface_recv_msg(struct interface *iface, struct in_addr *addr, void *buf, int MSG(NETWORK, "Received message on %s (id=%08x->%08x seq=%d len=%d)\n", interface_name(iface), msg.id, local_id, msg.seq, len); - inet_ntop(AF_INET, addr, addr_str, sizeof(addr_str)); - host = interface_get_host(addr_str, msg.id); usteer_node_set_blob(&host->host_info, msg.host_info); @@ -325,11 +322,12 @@ interface_find_by_ifindex(int index) } static void -interface_recv(struct uloop_fd *u, unsigned int events) +interface_recv_v4(struct uloop_fd *u, unsigned int events) { static char buf[APMGR_BUFLEN]; static char cmsg_buf[( CMSG_SPACE(sizeof(struct in_pktinfo)) + sizeof(int)) + 1]; static struct sockaddr_in sin; + char addr_str[INET_ADDRSTRLEN]; static struct iovec iov = { .iov_base = buf, .iov_len = sizeof(buf) @@ -381,11 +379,80 @@ interface_recv(struct uloop_fd *u, unsigned int events) continue; } - interface_recv_msg(iface, &sin.sin_addr, buf, len); + inet_ntop(AF_INET, &sin.sin_addr, addr_str, sizeof(addr_str)); + + interface_recv_msg(iface, addr_str, buf, len); } while (1); } -static void interface_send_msg(struct interface *iface, struct blob_attr *data) + +static void interface_recv_v6(struct uloop_fd *u, unsigned int events){ + static char buf[APMGR_BUFLEN]; + static char cmsg_buf[( CMSG_SPACE(sizeof(struct in6_pktinfo)) + sizeof(int)) + 1]; + static struct sockaddr_in6 sin; + static struct iovec iov = { + .iov_base = buf, + .iov_len = sizeof(buf) + }; + static struct msghdr msg = { + .msg_name = &sin, + .msg_namelen = sizeof(sin), + .msg_iov = &iov, + .msg_iovlen = 1, + .msg_control = cmsg_buf, + .msg_controllen = sizeof(cmsg_buf), + }; + struct cmsghdr *cmsg; + char addr_str[INET6_ADDRSTRLEN]; + int len; + + do { + struct in6_pktinfo *pkti = NULL; + struct interface *iface; + + len = recvmsg(u->fd, &msg, 0); + if (len < 0) { + switch (errno) { + case EAGAIN: + return; + case EINTR: + continue; + default: + perror("recvmsg"); + uloop_fd_delete(u); + return; + } + } + + for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) { + if (cmsg->cmsg_type != IPV6_PKTINFO) + continue; + + pkti = (struct in6_pktinfo *) CMSG_DATA(cmsg); + } + + if (!pkti) { + MSG(DEBUG, "Received packet without ifindex\n"); + continue; + } + + iface = interface_find_by_ifindex(pkti->ipi6_ifindex); + if (!iface) { + MSG(DEBUG, "Received packet from unconfigured interface %d\n", pkti->ipi6_ifindex); + continue; + } + + inet_ntop(AF_INET6, &sin.sin6_addr, addr_str, sizeof(addr_str)); + if (sin.sin6_addr.s6_addr[0] == 0) { + /* IPv4 mapped address. Ignore. */ + continue; + } + + interface_recv_msg(iface, addr_str, buf, len); + } while (1); +} + +static void interface_send_msg_v4(struct interface *iface, struct blob_attr *data) { static size_t cmsg_data[( CMSG_SPACE(sizeof(struct in_pktinfo)) / sizeof(size_t)) + 1]; static struct sockaddr_in a; @@ -421,6 +488,28 @@ static void interface_send_msg(struct interface *iface, struct blob_attr *data) perror("sendmsg"); } + +static void interface_send_msg_v6(struct interface *iface, struct blob_attr *data) { + static struct sockaddr_in6 groupSock = {}; + + groupSock.sin6_family = AF_INET6; + inet_pton(AF_INET6, APMGR_V6_MCAST_GROUP, &groupSock.sin6_addr); + groupSock.sin6_port = htons(APMGR_PORT); + + setsockopt(remote_fd.fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &iface->ifindex, sizeof(iface->ifindex)); + + if (sendto(remote_fd.fd, data, blob_pad_len(data), 0, (const struct sockaddr *)&groupSock, sizeof(groupSock)) < 0) + perror("sendmsg"); +} + +static void interface_send_msg(struct interface *iface, struct blob_attr *data){ + if (config.ipv6) { + interface_send_msg_v6(iface, data); + } else { + interface_send_msg_v4(iface, data); + } +} + static void usteer_send_sta_info(struct sta_info *sta) { int seen = current_time - sta->seen; @@ -558,23 +647,16 @@ usteer_init_local_id(void) return 0; } -static void -usteer_reload_timer(struct uloop_timeout *t) -{ +static int usteer_create_v4_socket() { int yes = 1; int fd; - if (remote_fd.registered) { - uloop_fd_delete(&remote_fd); - close(remote_fd.fd); - } - fd = usock(USOCK_UDP | USOCK_SERVER | USOCK_NONBLOCK | USOCK_NUMERIC | USOCK_IPV4ONLY, "0.0.0.0", APMGR_PORT_STR); if (fd < 0) { perror("usock"); - return; + return - 1; } if (setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &yes, sizeof(yes)) < 0) @@ -583,8 +665,62 @@ usteer_reload_timer(struct uloop_timeout *t) if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &yes, sizeof(yes)) < 0) perror("setsockopt(SO_BROADCAST)"); - remote_fd.fd = fd; - remote_fd.cb = interface_recv; + return fd; +} + + +static int usteer_create_v6_socket() { + struct interface *iface; + struct ipv6_mreq group; + int yes = 1; + int fd; + + fd = usock(USOCK_UDP | USOCK_SERVER | USOCK_NONBLOCK | + USOCK_NUMERIC | USOCK_IPV6ONLY, + "::", APMGR_PORT_STR); + if (fd < 0) { + perror("usock"); + return fd; + } + + if (!inet_pton(AF_INET6, APMGR_V6_MCAST_GROUP, &group.ipv6mr_multiaddr.s6_addr)) + perror("inet_pton(AF_INET6)"); + + /* Membership has to be added for every interface we listen on. */ + vlist_for_each_element(&interfaces, iface, node) { + printf("Adding group membership for %s on interface %d", APMGR_V6_MCAST_GROUP, iface->ifindex); + group.ipv6mr_interface = iface->ifindex; + if(setsockopt(fd, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, (char *)&group, sizeof group) < 0) + perror("setsockopt(IPV6_ADD_MEMBERSHIP)"); + } + + if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &yes, sizeof(yes)) < 0) + perror("setsockopt(IPV6_RECVPKTINFO)"); + + if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &yes, sizeof(yes)) < 0) + perror("setsockopt(SO_BROADCAST)"); + + return fd; +} + +static void usteer_reload_timer(struct uloop_timeout *t) { + /* Remove uloop descriptor */ + if (remote_fd.fd && remote_fd.registered) { + uloop_fd_delete(&remote_fd); + close(remote_fd.fd); + } + + if (config.ipv6) { + remote_fd.fd = usteer_create_v6_socket(); + remote_fd.cb = interface_recv_v6; + } else { + remote_fd.fd = usteer_create_v4_socket(); + remote_fd.cb = interface_recv_v4; + } + + if (remote_fd.fd < 0) + return; + uloop_fd_add(&remote_fd, ULOOP_READ); } diff --git a/ubus.c b/ubus.c index fe36384..00843ef 100644 --- a/ubus.c +++ b/ubus.c @@ -142,6 +142,7 @@ struct cfg_item { #define __config_items \ _cfg(BOOL, syslog), \ _cfg(U32, debug_level), \ + _cfg(BOOL, ipv6), \ _cfg(U32, sta_block_timeout), \ _cfg(U32, local_sta_timeout), \ _cfg(U32, local_sta_update), \ @@ -264,6 +265,8 @@ usteer_ubus_set_config(struct ubus_context *ctx, struct ubus_object *obj, } } + usteer_interface_init(); + return 0; } diff --git a/usteer.h b/usteer.h index 749075e..4ed3b95 100644 --- a/usteer.h +++ b/usteer.h @@ -33,6 +33,9 @@ #define __STR(x) #x #define _STR(x) __STR(x) + +#define APMGR_V6_MCAST_GROUP "ff02::4321" + #define APMGR_PORT 16720 /* AP */ #define APMGR_PORT_STR _STR(APMGR_PORT) #define APMGR_BUFLEN (64 * 1024) @@ -122,6 +125,8 @@ struct usteer_config { bool syslog; uint32_t debug_level; + bool ipv6; + uint32_t sta_block_timeout; uint32_t local_sta_timeout; uint32_t local_sta_update;