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.