From 4db216fcf72efbccad90e723de4508fd1697bb2f Mon Sep 17 00:00:00 2001 From: Janusz Dziedzic Date: Mon, 24 Feb 2014 13:22:16 +0100 Subject: [PATCH] wpa_supplicant: Add support for IPv6 with UDP ctrl_iface Add IPv6 support when using udp/udp-remote control interface using the following new build configuration options: CONFIG_CTRL_IFACE=udp6 CONFIG_CTRL_IFACE=udp6-remote This is useful for testing, while we don't need to assign IPv4 address (static or using DHCP) and can just use auto configured IPv6 addresses (link local, which is based on the MAC address). Also add scope id support for link local case. For example, ./wpa_cli ./wpa_cli -i ::1,9877 ./wpa_cli -i fe80::203:7fff:fe05:69%wlan0,9877 Signed-off-by: Janusz Dziedzic --- src/common/wpa_ctrl.c | 69 +++++++++++++++++++++- wpa_supplicant/Makefile | 11 ++++ wpa_supplicant/ctrl_iface_udp.c | 101 +++++++++++++++++++++++++++++++- wpa_supplicant/defconfig | 2 + 4 files changed, 177 insertions(+), 6 deletions(-) diff --git a/src/common/wpa_ctrl.c b/src/common/wpa_ctrl.c index f4af94aa1..5820a1364 100644 --- a/src/common/wpa_ctrl.c +++ b/src/common/wpa_ctrl.c @@ -25,6 +25,10 @@ #include "private/android_filesystem_config.h" #endif /* ANDROID */ +#ifdef CONFIG_CTRL_IFACE_UDP_IPV6 +#include +#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */ + #include "wpa_ctrl.h" #include "common.h" @@ -46,8 +50,13 @@ struct wpa_ctrl { #ifdef CONFIG_CTRL_IFACE_UDP int s; +#ifdef CONFIG_CTRL_IFACE_UDP_IPV6 + struct sockaddr_in6 local; + struct sockaddr_in6 dest; +#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */ struct sockaddr_in local; struct sockaddr_in dest; +#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */ char *cookie; char *remote_ifname; char *remote_ip; @@ -279,19 +288,33 @@ struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path) return NULL; os_memset(ctrl, 0, sizeof(*ctrl)); +#ifdef CONFIG_CTRL_IFACE_UDP_IPV6 + ctrl->s = socket(PF_INET6, SOCK_DGRAM, 0); +#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */ ctrl->s = socket(PF_INET, SOCK_DGRAM, 0); +#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */ if (ctrl->s < 0) { perror("socket"); os_free(ctrl); return NULL; } +#ifdef CONFIG_CTRL_IFACE_UDP_IPV6 + ctrl->local.sin6_family = AF_INET6; +#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE + ctrl->local.sin6_addr = in6addr_any; +#else /* CONFIG_CTRL_IFACE_UDP_REMOTE */ + inet_pton(AF_INET6, "::1", &ctrl->local.sin6_addr); +#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */ +#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */ ctrl->local.sin_family = AF_INET; #ifdef CONFIG_CTRL_IFACE_UDP_REMOTE ctrl->local.sin_addr.s_addr = INADDR_ANY; #else /* CONFIG_CTRL_IFACE_UDP_REMOTE */ ctrl->local.sin_addr.s_addr = htonl((127 << 24) | 1); #endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */ +#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */ + if (bind(ctrl->s, (struct sockaddr *) &ctrl->local, sizeof(ctrl->local)) < 0) { close(ctrl->s); @@ -299,14 +322,24 @@ struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path) return NULL; } +#ifdef CONFIG_CTRL_IFACE_UDP_IPV6 + ctrl->dest.sin6_family = AF_INET6; + inet_pton(AF_INET6, "::1", &ctrl->dest.sin6_addr); + ctrl->dest.sin6_port = htons(WPA_CTRL_IFACE_PORT); +#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */ ctrl->dest.sin_family = AF_INET; ctrl->dest.sin_addr.s_addr = htonl((127 << 24) | 1); ctrl->dest.sin_port = htons(WPA_CTRL_IFACE_PORT); +#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */ #ifdef CONFIG_CTRL_IFACE_UDP_REMOTE if (ctrl_path) { char *port, *name; int port_id; +#ifdef CONFIG_CTRL_IFACE_UDP_IPV6 + char *scope; + int scope_id = 0; +#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */ name = os_strdup(ctrl_path); if (name == NULL) { @@ -314,7 +347,11 @@ struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path) os_free(ctrl); return NULL; } +#ifdef CONFIG_CTRL_IFACE_UDP_IPV6 + port = os_strchr(name, ','); +#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */ port = os_strchr(name, ':'); +#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */ if (port) { port_id = atoi(&port[1]); @@ -322,7 +359,16 @@ struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path) } else port_id = WPA_CTRL_IFACE_PORT; +#ifdef CONFIG_CTRL_IFACE_UDP_IPV6 + scope = os_strchr(name, '%'); + if (scope) { + scope_id = if_nametoindex(&scope[1]); + scope[0] = '\0'; + } + h = gethostbyname2(name, AF_INET6); +#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */ h = gethostbyname(name); +#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */ ctrl->remote_ip = os_strdup(name); os_free(name); if (h == NULL) { @@ -332,16 +378,33 @@ struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path) os_free(ctrl); return NULL; } +#ifdef CONFIG_CTRL_IFACE_UDP_IPV6 + ctrl->dest.sin6_scope_id = scope_id; + ctrl->dest.sin6_port = htons(port_id); + os_memcpy(&ctrl->dest.sin6_addr, h->h_addr, h->h_length); +#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */ ctrl->dest.sin_port = htons(port_id); - os_memcpy(h->h_addr, (char *) &ctrl->dest.sin_addr.s_addr, - h->h_length); + os_memcpy(&ctrl->dest.sin_addr.s_addr, h->h_addr, h->h_length); +#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */ } else ctrl->remote_ip = os_strdup("localhost"); #endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */ if (connect(ctrl->s, (struct sockaddr *) &ctrl->dest, sizeof(ctrl->dest)) < 0) { - perror("connect"); +#ifdef CONFIG_CTRL_IFACE_UDP_IPV6 + char addr[INET6_ADDRSTRLEN]; + wpa_printf(MSG_ERROR, "connect(%s:%d) failed: %s", + inet_ntop(AF_INET6, &ctrl->dest.sin6_addr, addr, + sizeof(ctrl->dest)), + ntohs(ctrl->dest.sin6_port), + strerror(errno)); +#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */ + wpa_printf(MSG_ERROR, "connect(%s:%d) failed: %s", + inet_ntoa(ctrl->dest.sin_addr), + ntohs(ctrl->dest.sin_port), + strerror(errno)); +#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */ close(ctrl->s); os_free(ctrl->remote_ip); os_free(ctrl); diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile index 7b556e84d..b9c8a4688 100644 --- a/wpa_supplicant/Makefile +++ b/wpa_supplicant/Makefile @@ -1267,6 +1267,11 @@ endif ifeq ($(CONFIG_CTRL_IFACE), udp) CFLAGS += -DCONFIG_CTRL_IFACE_UDP endif +ifeq ($(CONFIG_CTRL_IFACE), udp6) +CONFIG_CTRL_IFACE=udp +CFLAGS += -DCONFIG_CTRL_IFACE_UDP +CFLAGS += -DCONFIG_CTRL_IFACE_UDP_IPV6 +endif ifeq ($(CONFIG_CTRL_IFACE), named_pipe) CFLAGS += -DCONFIG_CTRL_IFACE_NAMED_PIPE endif @@ -1275,6 +1280,12 @@ CONFIG_CTRL_IFACE=udp CFLAGS += -DCONFIG_CTRL_IFACE_UDP CFLAGS += -DCONFIG_CTRL_IFACE_UDP_REMOTE endif +ifeq ($(CONFIG_CTRL_IFACE), udp6-remote) +CONFIG_CTRL_IFACE=udp +CFLAGS += -DCONFIG_CTRL_IFACE_UDP +CFLAGS += -DCONFIG_CTRL_IFACE_UDP_REMOTE +CFLAGS += -DCONFIG_CTRL_IFACE_UDP_IPV6 +endif OBJS += ctrl_iface.o ctrl_iface_$(CONFIG_CTRL_IFACE).o endif diff --git a/wpa_supplicant/ctrl_iface_udp.c b/wpa_supplicant/ctrl_iface_udp.c index 8c09ba133..9d0674de0 100644 --- a/wpa_supplicant/ctrl_iface_udp.c +++ b/wpa_supplicant/ctrl_iface_udp.c @@ -30,7 +30,11 @@ */ struct wpa_ctrl_dst { struct wpa_ctrl_dst *next; +#ifdef CONFIG_CTRL_IFACE_UDP_IPV6 + struct sockaddr_in6 addr; +#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */ struct sockaddr_in addr; +#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */ socklen_t addrlen; int debug_level; int errors; @@ -51,38 +55,68 @@ static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv, static int wpa_supplicant_ctrl_iface_attach(struct ctrl_iface_priv *priv, +#ifdef CONFIG_CTRL_IFACE_UDP_IPV6 + struct sockaddr_in6 *from, +#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */ struct sockaddr_in *from, +#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */ socklen_t fromlen) { struct wpa_ctrl_dst *dst; +#ifdef CONFIG_CTRL_IFACE_UDP_IPV6 + char addr[INET6_ADDRSTRLEN]; +#endif /* CONFIG_UDP_IPV6 */ dst = os_zalloc(sizeof(*dst)); if (dst == NULL) return -1; - os_memcpy(&dst->addr, from, sizeof(struct sockaddr_in)); + os_memcpy(&dst->addr, from, sizeof(*from)); dst->addrlen = fromlen; dst->debug_level = MSG_INFO; dst->next = priv->ctrl_dst; priv->ctrl_dst = dst; +#ifdef CONFIG_CTRL_IFACE_UDP_IPV6 + wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor attached %s:%d", + inet_ntop(AF_INET6, &from->sin6_addr, addr, sizeof(*from)), + ntohs(from->sin6_port)); +#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */ wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor attached %s:%d", inet_ntoa(from->sin_addr), ntohs(from->sin_port)); +#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */ return 0; } static int wpa_supplicant_ctrl_iface_detach(struct ctrl_iface_priv *priv, +#ifdef CONFIG_CTRL_IFACE_UDP_IPV6 + struct sockaddr_in6 *from, +#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */ struct sockaddr_in *from, +#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */ socklen_t fromlen) { struct wpa_ctrl_dst *dst, *prev = NULL; +#ifdef CONFIG_CTRL_IFACE_UDP_IPV6 + char addr[INET6_ADDRSTRLEN]; +#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */ dst = priv->ctrl_dst; while (dst) { +#ifdef CONFIG_CTRL_IFACE_UDP_IPV6 + if (from->sin6_port == dst->addr.sin6_port && + !os_memcmp(&from->sin6_addr, &dst->addr.sin6_addr, + sizeof(from->sin6_addr))) { + wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor detached %s:%d", + inet_ntop(AF_INET6, &from->sin6_addr, addr, + sizeof(*from)), + ntohs(from->sin6_port)); +#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */ if (from->sin_addr.s_addr == dst->addr.sin_addr.s_addr && from->sin_port == dst->addr.sin_port) { wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor detached " "%s:%d", inet_ntoa(from->sin_addr), ntohs(from->sin_port)); +#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */ if (prev == NULL) priv->ctrl_dst = dst->next; else @@ -98,21 +132,38 @@ static int wpa_supplicant_ctrl_iface_detach(struct ctrl_iface_priv *priv, static int wpa_supplicant_ctrl_iface_level(struct ctrl_iface_priv *priv, +#ifdef CONFIG_CTRL_IFACE_UDP_IPV6 + struct sockaddr_in6 *from, +#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */ struct sockaddr_in *from, +#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */ socklen_t fromlen, char *level) { struct wpa_ctrl_dst *dst; +#ifdef CONFIG_CTRL_IFACE_UDP_IPV6 + char addr[INET6_ADDRSTRLEN]; +#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */ wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", level); dst = priv->ctrl_dst; while (dst) { +#if CONFIG_CTRL_IFACE_UDP_IPV6 + if (from->sin6_port == dst->addr.sin6_port && + !os_memcmp(&from->sin6_addr, &dst->addr.sin6_addr, + sizeof(from->sin6_addr))) { + wpa_printf(MSG_DEBUG, "CTRL_IFACE changed monitor level %s:%d", + inet_ntop(AF_INET6, &from->sin6_addr, addr, + sizeof(*from)), + ntohs(from->sin6_port)); +#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */ if (from->sin_addr.s_addr == dst->addr.sin_addr.s_addr && from->sin_port == dst->addr.sin_port) { wpa_printf(MSG_DEBUG, "CTRL_IFACE changed monitor " "level %s:%d", inet_ntoa(from->sin_addr), ntohs(from->sin_port)); +#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */ dst->debug_level = atoi(level); return 0; } @@ -150,7 +201,14 @@ static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx, struct ctrl_iface_priv *priv = sock_ctx; char buf[256], *pos; int res; +#ifdef CONFIG_CTRL_IFACE_UDP_IPV6 + struct sockaddr_in6 from; +#ifndef CONFIG_CTRL_IFACE_UDP_REMOTE + char addr[INET6_ADDRSTRLEN]; +#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */ +#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */ struct sockaddr_in from; +#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */ socklen_t fromlen = sizeof(from); char *reply = NULL; size_t reply_len = 0; @@ -165,6 +223,13 @@ static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx, } #ifndef CONFIG_CTRL_IFACE_UDP_REMOTE +#ifdef CONFIG_CTRL_IFACE_UDP_IPV6 + inet_ntop(AF_INET6, &from.sin6_addr, addr, sizeof(from)); + if (os_strcmp(addr, "::1")) { + wpa_printf(MSG_DEBUG, "CTRL: Drop packet from unexpected source %s", + addr); + } +#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */ if (from.sin_addr.s_addr != htonl((127 << 24) | 1)) { /* * The OS networking stack is expected to drop this kind of @@ -176,6 +241,7 @@ static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx, "source %s", inet_ntoa(from.sin_addr)); return; } +#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */ #endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */ buf[res] = '\0'; @@ -269,8 +335,14 @@ struct ctrl_iface_priv * wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s) { struct ctrl_iface_priv *priv; - struct sockaddr_in addr; int port = WPA_CTRL_IFACE_PORT; +#ifdef CONFIG_CTRL_IFACE_UDP_IPV6 + struct sockaddr_in6 addr; + int domain = PF_INET6; +#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */ + struct sockaddr_in addr; + int domain = PF_INET; +#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */ priv = os_zalloc(sizeof(*priv)); if (priv == NULL) @@ -282,21 +354,34 @@ wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s) if (wpa_s->conf->ctrl_interface == NULL) return priv; - priv->sock = socket(PF_INET, SOCK_DGRAM, 0); + priv->sock = socket(domain, SOCK_DGRAM, 0); if (priv->sock < 0) { perror("socket(PF_INET)"); goto fail; } os_memset(&addr, 0, sizeof(addr)); +#ifdef CONFIG_CTRL_IFACE_UDP_IPV6 + addr.sin6_family = AF_INET6; +#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE + addr.sin6_addr = in6addr_any; +#else /* CONFIG_CTRL_IFACE_UDP_REMOTE */ + inet_pton(AF_INET6, "::1", &addr.sin6_addr); +#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */ +#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */ addr.sin_family = AF_INET; #ifdef CONFIG_CTRL_IFACE_UDP_REMOTE addr.sin_addr.s_addr = INADDR_ANY; #else /* CONFIG_CTRL_IFACE_UDP_REMOTE */ addr.sin_addr.s_addr = htonl((127 << 24) | 1); #endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */ +#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */ try_again: +#ifdef CONFIG_CTRL_IFACE_UDP_IPV6 + addr.sin6_port = htons(port); +#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */ addr.sin_port = htons(port); +#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */ if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { port--; if ((WPA_CTRL_IFACE_PORT - port) < WPA_CTRL_IFACE_PORT_LIMIT) @@ -362,6 +447,9 @@ static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv, int idx; char *sbuf; int llen; +#ifdef CONFIG_CTRL_IFACE_UDP_IPV6 + char addr[INET6_ADDRSTRLEN]; +#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */ dst = priv->ctrl_dst; if (priv->sock < 0 || dst == NULL) @@ -381,9 +469,16 @@ static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv, while (dst) { next = dst->next; if (level >= dst->debug_level) { +#ifdef CONFIG_CTRL_IFACE_UDP_IPV6 + wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor send %s:%d", + inet_ntop(AF_INET6, &dst->addr.sin6_addr, + addr, sizeof(dst->addr)), + ntohs(dst->addr.sin6_port)); +#else /* CONFIG_CTRL_IFACE_UDP_IPV6 */ wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor send %s:%d", inet_ntoa(dst->addr.sin_addr), ntohs(dst->addr.sin_port)); +#endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */ if (sendto(priv->sock, sbuf, llen + len, 0, (struct sockaddr *) &dst->addr, sizeof(dst->addr)) < 0) { diff --git a/wpa_supplicant/defconfig b/wpa_supplicant/defconfig index 6684782c4..91eea3550 100644 --- a/wpa_supplicant/defconfig +++ b/wpa_supplicant/defconfig @@ -192,8 +192,10 @@ CONFIG_SMARTCARD=y # Select control interface backend for external programs, e.g, wpa_cli: # unix = UNIX domain sockets (default for Linux/*BSD) # udp = UDP sockets using localhost (127.0.0.1) +# udp6 = UDP IPv6 sockets using localhost (::1) # named_pipe = Windows Named Pipe (default for Windows) # udp-remote = UDP sockets with remote access (only for tests systems/purpose) +# udp6-remote = UDP IPv6 sockets with remote access (only for tests purpose) # y = use default (backwards compatibility) # If this option is commented out, control interface is not included in the # build. -- 2.39.2