2 * WPA Supplicant / UDP socket -based control interface
3 * Copyright (c) 2004-2005, Jouni Malinen <j@w1.fi>
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
14 #include "eapol_supp/eapol_supp_sm.h"
15 #include "wpa_supplicant_i.h"
16 #include "ctrl_iface.h"
17 #include "common/wpa_ctrl.h"
22 /* Per-interface ctrl_iface */
25 * struct wpa_ctrl_dst - Internal data structure of control interface monitors
27 * This structure is used to store information about registered control
28 * interface monitors into struct wpa_supplicant. This data is private to
29 * ctrl_iface_udp.c and should not be touched directly from other files.
32 struct wpa_ctrl_dst *next;
33 #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
34 struct sockaddr_in6 addr;
35 #else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
36 struct sockaddr_in addr;
37 #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
44 struct ctrl_iface_priv {
45 struct wpa_supplicant *wpa_s;
47 struct wpa_ctrl_dst *ctrl_dst;
48 u8 cookie[COOKIE_LEN];
52 static void wpa_supplicant_ctrl_iface_send(struct wpa_supplicant *wpa_s,
53 const char *ifname, int sock,
54 struct wpa_ctrl_dst **head,
55 int level, const char *buf,
59 static int wpa_supplicant_ctrl_iface_attach(struct wpa_ctrl_dst **head,
60 #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
61 struct sockaddr_in6 *from,
62 #else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
63 struct sockaddr_in *from,
64 #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
67 struct wpa_ctrl_dst *dst;
68 #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
69 char addr[INET6_ADDRSTRLEN];
70 #endif /* CONFIG_UDP_IPV6 */
72 dst = os_zalloc(sizeof(*dst));
75 os_memcpy(&dst->addr, from, sizeof(*from));
76 dst->addrlen = fromlen;
77 dst->debug_level = MSG_INFO;
80 #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
81 wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor attached %s:%d",
82 inet_ntop(AF_INET6, &from->sin6_addr, addr, sizeof(*from)),
83 ntohs(from->sin6_port));
84 #else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
85 wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor attached %s:%d",
86 inet_ntoa(from->sin_addr), ntohs(from->sin_port));
87 #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
92 static int wpa_supplicant_ctrl_iface_detach(struct wpa_ctrl_dst **head,
93 #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
94 struct sockaddr_in6 *from,
95 #else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
96 struct sockaddr_in *from,
97 #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
100 struct wpa_ctrl_dst *dst, *prev = NULL;
101 #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
102 char addr[INET6_ADDRSTRLEN];
103 #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
107 #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
108 if (from->sin6_port == dst->addr.sin6_port &&
109 !os_memcmp(&from->sin6_addr, &dst->addr.sin6_addr,
110 sizeof(from->sin6_addr))) {
111 wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor detached %s:%d",
112 inet_ntop(AF_INET6, &from->sin6_addr, addr,
114 ntohs(from->sin6_port));
115 #else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
116 if (from->sin_addr.s_addr == dst->addr.sin_addr.s_addr &&
117 from->sin_port == dst->addr.sin_port) {
118 wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor detached "
119 "%s:%d", inet_ntoa(from->sin_addr),
120 ntohs(from->sin_port));
121 #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
125 prev->next = dst->next;
136 static int wpa_supplicant_ctrl_iface_level(struct ctrl_iface_priv *priv,
137 #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
138 struct sockaddr_in6 *from,
139 #else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
140 struct sockaddr_in *from,
141 #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
145 struct wpa_ctrl_dst *dst;
146 #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
147 char addr[INET6_ADDRSTRLEN];
148 #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
150 wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", level);
152 dst = priv->ctrl_dst;
154 #if CONFIG_CTRL_IFACE_UDP_IPV6
155 if (from->sin6_port == dst->addr.sin6_port &&
156 !os_memcmp(&from->sin6_addr, &dst->addr.sin6_addr,
157 sizeof(from->sin6_addr))) {
158 wpa_printf(MSG_DEBUG, "CTRL_IFACE changed monitor level %s:%d",
159 inet_ntop(AF_INET6, &from->sin6_addr, addr,
161 ntohs(from->sin6_port));
162 #else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
163 if (from->sin_addr.s_addr == dst->addr.sin_addr.s_addr &&
164 from->sin_port == dst->addr.sin_port) {
165 wpa_printf(MSG_DEBUG, "CTRL_IFACE changed monitor "
166 "level %s:%d", inet_ntoa(from->sin_addr),
167 ntohs(from->sin_port));
168 #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
169 dst->debug_level = atoi(level);
180 wpa_supplicant_ctrl_iface_get_cookie(struct ctrl_iface_priv *priv,
184 reply = os_malloc(7 + 2 * COOKIE_LEN + 1);
190 os_memcpy(reply, "COOKIE=", 7);
191 wpa_snprintf_hex(reply + 7, 2 * COOKIE_LEN + 1,
192 priv->cookie, COOKIE_LEN);
194 *reply_len = 7 + 2 * COOKIE_LEN;
199 static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx,
202 struct wpa_supplicant *wpa_s = eloop_ctx;
203 struct ctrl_iface_priv *priv = sock_ctx;
206 #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
207 struct sockaddr_in6 from;
208 #ifndef CONFIG_CTRL_IFACE_UDP_REMOTE
209 char addr[INET6_ADDRSTRLEN];
210 #endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
211 #else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
212 struct sockaddr_in from;
213 #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
214 socklen_t fromlen = sizeof(from);
216 size_t reply_len = 0;
217 int new_attached = 0;
218 u8 cookie[COOKIE_LEN];
220 res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
221 (struct sockaddr *) &from, &fromlen);
223 wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s",
228 #ifndef CONFIG_CTRL_IFACE_UDP_REMOTE
229 #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
230 inet_ntop(AF_INET6, &from.sin6_addr, addr, sizeof(from));
231 if (os_strcmp(addr, "::1")) {
232 wpa_printf(MSG_DEBUG, "CTRL: Drop packet from unexpected source %s",
235 #else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
236 if (from.sin_addr.s_addr != htonl((127 << 24) | 1)) {
238 * The OS networking stack is expected to drop this kind of
239 * frames since the socket is bound to only localhost address.
240 * Just in case, drop the frame if it is coming from any other
243 wpa_printf(MSG_DEBUG, "CTRL: Drop packet from unexpected "
244 "source %s", inet_ntoa(from.sin_addr));
247 #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
248 #endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
252 if (os_strcmp(buf, "GET_COOKIE") == 0) {
253 reply = wpa_supplicant_ctrl_iface_get_cookie(priv, &reply_len);
258 * Require that the client includes a prefix with the 'cookie' value
259 * fetched with GET_COOKIE command. This is used to verify that the
260 * client has access to a bidirectional link over UDP in order to
261 * avoid attacks using forged localhost IP address even if the OS does
262 * not block such frames from remote destinations.
264 if (os_strncmp(buf, "COOKIE=", 7) != 0) {
265 wpa_printf(MSG_DEBUG, "CTLR: No cookie in the request - "
270 if (hexstr2bin(buf + 7, cookie, COOKIE_LEN) < 0) {
271 wpa_printf(MSG_DEBUG, "CTLR: Invalid cookie format in the "
272 "request - drop request");
276 if (os_memcmp(cookie, priv->cookie, COOKIE_LEN) != 0) {
277 wpa_printf(MSG_DEBUG, "CTLR: Invalid cookie in the request - "
282 pos = buf + 7 + 2 * COOKIE_LEN;
286 if (os_strcmp(pos, "ATTACH") == 0) {
287 if (wpa_supplicant_ctrl_iface_attach(&priv->ctrl_dst,
294 } else if (os_strcmp(pos, "DETACH") == 0) {
295 if (wpa_supplicant_ctrl_iface_detach(&priv->ctrl_dst,
300 } else if (os_strncmp(pos, "LEVEL ", 6) == 0) {
301 if (wpa_supplicant_ctrl_iface_level(priv, &from, fromlen,
307 reply = wpa_supplicant_ctrl_iface_process(wpa_s, pos,
313 sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,
316 } else if (reply_len == 1) {
317 sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
319 } else if (reply_len == 2) {
320 sendto(sock, "OK\n", 3, 0, (struct sockaddr *) &from,
325 eapol_sm_notify_ctrl_attached(wpa_s->eapol);
329 static void wpa_supplicant_ctrl_iface_msg_cb(void *ctx, int level,
330 enum wpa_msg_type type,
331 const char *txt, size_t len)
333 struct wpa_supplicant *wpa_s = ctx;
334 if (wpa_s == NULL || wpa_s->ctrl_iface == NULL)
336 wpa_supplicant_ctrl_iface_send(wpa_s, NULL, wpa_s->ctrl_iface->sock,
337 &wpa_s->ctrl_iface->ctrl_dst,
342 struct ctrl_iface_priv *
343 wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
345 struct ctrl_iface_priv *priv;
346 int port = WPA_CTRL_IFACE_PORT;
348 #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
349 struct sockaddr_in6 addr;
350 int domain = PF_INET6;
351 #else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
352 struct sockaddr_in addr;
353 int domain = PF_INET;
354 #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
356 priv = os_zalloc(sizeof(*priv));
361 os_get_random(priv->cookie, COOKIE_LEN);
363 if (wpa_s->conf->ctrl_interface == NULL)
366 pos = os_strstr(wpa_s->conf->ctrl_interface, "udp:");
371 wpa_printf(MSG_ERROR, "Invalid ctrl_iface UDP port: %s",
372 wpa_s->conf->ctrl_interface);
377 priv->sock = socket(domain, SOCK_DGRAM, 0);
378 if (priv->sock < 0) {
379 wpa_printf(MSG_ERROR, "socket(PF_INET): %s", strerror(errno));
383 os_memset(&addr, 0, sizeof(addr));
384 #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
385 addr.sin6_family = AF_INET6;
386 #ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
387 addr.sin6_addr = in6addr_any;
388 #else /* CONFIG_CTRL_IFACE_UDP_REMOTE */
389 inet_pton(AF_INET6, "::1", &addr.sin6_addr);
390 #endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
391 #else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
392 addr.sin_family = AF_INET;
393 #ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
394 addr.sin_addr.s_addr = INADDR_ANY;
395 #else /* CONFIG_CTRL_IFACE_UDP_REMOTE */
396 addr.sin_addr.s_addr = htonl((127 << 24) | 1);
397 #endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
398 #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
400 #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
401 addr.sin6_port = htons(port);
402 #else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
403 addr.sin_port = htons(port);
404 #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
405 if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
407 if ((WPA_CTRL_IFACE_PORT - port) < WPA_CTRL_IFACE_PORT_LIMIT &&
410 wpa_printf(MSG_ERROR, "bind(AF_INET): %s", strerror(errno));
414 #ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
415 wpa_msg(wpa_s, MSG_DEBUG, "ctrl_iface_init UDP port: %d", port);
416 #endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
418 eloop_register_read_sock(priv->sock, wpa_supplicant_ctrl_iface_receive,
420 wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb);
432 void wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv)
434 struct wpa_ctrl_dst *dst, *prev;
436 if (priv->sock > -1) {
437 eloop_unregister_read_sock(priv->sock);
438 if (priv->ctrl_dst) {
440 * Wait before closing the control socket if
441 * there are any attached monitors in order to allow
442 * them to receive any pending messages.
444 wpa_printf(MSG_DEBUG, "CTRL_IFACE wait for attached "
445 "monitors to receive messages");
452 dst = priv->ctrl_dst;
462 static void wpa_supplicant_ctrl_iface_send(struct wpa_supplicant *wpa_s,
463 const char *ifname, int sock,
464 struct wpa_ctrl_dst **head,
465 int level, const char *buf,
468 struct wpa_ctrl_dst *dst, *next;
473 #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
474 char addr[INET6_ADDRSTRLEN];
475 #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
478 if (sock < 0 || dst == NULL)
482 os_snprintf(levelstr, sizeof(levelstr), "IFACE=%s <%d>",
485 os_snprintf(levelstr, sizeof(levelstr), "<%d>", level);
487 llen = os_strlen(levelstr);
488 sbuf = os_malloc(llen + len);
492 os_memcpy(sbuf, levelstr, llen);
493 os_memcpy(sbuf + llen, buf, len);
498 if (level >= dst->debug_level) {
499 #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
500 wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor send %s:%d",
501 inet_ntop(AF_INET6, &dst->addr.sin6_addr,
502 addr, sizeof(dst->addr)),
503 ntohs(dst->addr.sin6_port));
504 #else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
505 wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor send %s:%d",
506 inet_ntoa(dst->addr.sin_addr),
507 ntohs(dst->addr.sin_port));
508 #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
509 if (sendto(sock, sbuf, llen + len, 0,
510 (struct sockaddr *) &dst->addr,
511 sizeof(dst->addr)) < 0) {
512 wpa_printf(MSG_ERROR,
513 "sendto(CTRL_IFACE monitor): %s",
516 if (dst->errors > 10) {
517 wpa_supplicant_ctrl_iface_detach(
531 void wpa_supplicant_ctrl_iface_wait(struct ctrl_iface_priv *priv)
533 wpa_printf(MSG_DEBUG, "CTRL_IFACE - %s - wait for monitor",
534 priv->wpa_s->ifname);
535 eloop_wait_for_read_sock(priv->sock);
539 /* Global ctrl_iface */
541 struct ctrl_iface_global_priv {
543 u8 cookie[COOKIE_LEN];
548 wpa_supplicant_global_get_cookie(struct ctrl_iface_global_priv *priv,
552 reply = os_malloc(7 + 2 * COOKIE_LEN + 1);
558 os_memcpy(reply, "COOKIE=", 7);
559 wpa_snprintf_hex(reply + 7, 2 * COOKIE_LEN + 1,
560 priv->cookie, COOKIE_LEN);
562 *reply_len = 7 + 2 * COOKIE_LEN;
567 static void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx,
570 struct wpa_global *global = eloop_ctx;
571 struct ctrl_iface_global_priv *priv = sock_ctx;
574 struct sockaddr_in from;
575 socklen_t fromlen = sizeof(from);
578 u8 cookie[COOKIE_LEN];
580 res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
581 (struct sockaddr *) &from, &fromlen);
583 wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s",
588 #ifndef CONFIG_CTRL_IFACE_UDP_REMOTE
589 if (from.sin_addr.s_addr != htonl((127 << 24) | 1)) {
591 * The OS networking stack is expected to drop this kind of
592 * frames since the socket is bound to only localhost address.
593 * Just in case, drop the frame if it is coming from any other
596 wpa_printf(MSG_DEBUG, "CTRL: Drop packet from unexpected "
597 "source %s", inet_ntoa(from.sin_addr));
600 #endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
604 if (os_strcmp(buf, "GET_COOKIE") == 0) {
605 reply = wpa_supplicant_global_get_cookie(priv, &reply_len);
609 if (os_strncmp(buf, "COOKIE=", 7) != 0) {
610 wpa_printf(MSG_DEBUG, "CTLR: No cookie in the request - "
615 if (hexstr2bin(buf + 7, cookie, COOKIE_LEN) < 0) {
616 wpa_printf(MSG_DEBUG, "CTLR: Invalid cookie format in the "
617 "request - drop request");
621 if (os_memcmp(cookie, priv->cookie, COOKIE_LEN) != 0) {
622 wpa_printf(MSG_DEBUG, "CTLR: Invalid cookie in the request - "
627 pos = buf + 7 + 2 * COOKIE_LEN;
631 reply = wpa_supplicant_global_ctrl_iface_process(global, pos,
636 sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,
639 } else if (reply_len) {
640 sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
646 struct ctrl_iface_global_priv *
647 wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global)
649 struct ctrl_iface_global_priv *priv;
650 struct sockaddr_in addr;
652 int port = WPA_GLOBAL_CTRL_IFACE_PORT;
654 priv = os_zalloc(sizeof(*priv));
658 os_get_random(priv->cookie, COOKIE_LEN);
660 if (global->params.ctrl_interface == NULL)
663 wpa_printf(MSG_DEBUG, "Global control interface '%s'",
664 global->params.ctrl_interface);
666 pos = os_strstr(global->params.ctrl_interface, "udp:");
671 wpa_printf(MSG_ERROR, "Invalid global ctrl UDP port %s",
672 global->params.ctrl_interface);
677 priv->sock = socket(PF_INET, SOCK_DGRAM, 0);
678 if (priv->sock < 0) {
679 wpa_printf(MSG_ERROR, "socket(PF_INET): %s", strerror(errno));
683 os_memset(&addr, 0, sizeof(addr));
684 addr.sin_family = AF_INET;
685 #ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
686 addr.sin_addr.s_addr = INADDR_ANY;
687 #else /* CONFIG_CTRL_IFACE_UDP_REMOTE */
688 addr.sin_addr.s_addr = htonl((127 << 24) | 1);
689 #endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
691 addr.sin_port = htons(port);
692 if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
694 if ((port - WPA_GLOBAL_CTRL_IFACE_PORT) <
695 WPA_GLOBAL_CTRL_IFACE_PORT_LIMIT && !pos)
697 wpa_printf(MSG_ERROR, "bind(AF_INET): %s", strerror(errno));
701 #ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
702 wpa_printf(MSG_DEBUG, "global_ctrl_iface_init UDP port: %d", port);
703 #endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
705 eloop_register_read_sock(priv->sock,
706 wpa_supplicant_global_ctrl_iface_receive,
720 wpa_supplicant_global_ctrl_iface_deinit(struct ctrl_iface_global_priv *priv)
722 if (priv->sock >= 0) {
723 eloop_unregister_read_sock(priv->sock);