xref: /freebsd/contrib/wpa/wpa_supplicant/ctrl_iface_udp.c (revision d4eeb02986980bf33dd56c41ceb9fc5f180c0d47)
1 /*
2  * WPA Supplicant / UDP socket -based control interface
3  * Copyright (c) 2004-2020, Jouni Malinen <j@w1.fi>
4  *
5  * This software may be distributed under the terms of the BSD license.
6  * See README for more details.
7  */
8 
9 #include "includes.h"
10 
11 #include "common.h"
12 #include "eloop.h"
13 #include "config.h"
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"
18 
19 
20 #define COOKIE_LEN 8
21 
22 /* Per-interface ctrl_iface */
23 
24 /**
25  * struct wpa_ctrl_dst - Internal data structure of control interface monitors
26  *
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.
30  */
31 struct wpa_ctrl_dst {
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 */
38 	socklen_t addrlen;
39 	int debug_level;
40 	int errors;
41 };
42 
43 
44 struct ctrl_iface_priv {
45 	struct wpa_supplicant *wpa_s;
46 	int sock;
47 	struct wpa_ctrl_dst *ctrl_dst;
48 	u8 cookie[COOKIE_LEN];
49 };
50 
51 struct ctrl_iface_global_priv {
52 	int sock;
53 	struct wpa_ctrl_dst *ctrl_dst;
54 	u8 cookie[COOKIE_LEN];
55 };
56 
57 
58 static void wpa_supplicant_ctrl_iface_send(struct wpa_supplicant *wpa_s,
59 					   const char *ifname, int sock,
60 					   struct wpa_ctrl_dst **head,
61 					   int level, const char *buf,
62 					   size_t len);
63 
64 
65 static void wpas_ctrl_iface_free_dst(struct wpa_ctrl_dst *dst)
66 {
67 	struct wpa_ctrl_dst *prev;
68 
69 	while (dst) {
70 		prev = dst;
71 		dst = dst->next;
72 		os_free(prev);
73 	}
74 }
75 
76 
77 static int wpa_supplicant_ctrl_iface_attach(struct wpa_ctrl_dst **head,
78 #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
79 					    struct sockaddr_in6 *from,
80 #else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
81 					    struct sockaddr_in *from,
82 #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
83 					    socklen_t fromlen)
84 {
85 	struct wpa_ctrl_dst *dst;
86 #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
87 	char addr[INET6_ADDRSTRLEN];
88 #endif /* CONFIG_UDP_IPV6 */
89 
90 	dst = os_zalloc(sizeof(*dst));
91 	if (dst == NULL)
92 		return -1;
93 	os_memcpy(&dst->addr, from, sizeof(*from));
94 	dst->addrlen = fromlen;
95 	dst->debug_level = MSG_INFO;
96 	dst->next = *head;
97 	*head = dst;
98 #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
99 	wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor attached %s:%d",
100 		   inet_ntop(AF_INET6, &from->sin6_addr, addr, sizeof(*from)),
101 		   ntohs(from->sin6_port));
102 #else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
103 	wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor attached %s:%d",
104 		   inet_ntoa(from->sin_addr), ntohs(from->sin_port));
105 #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
106 	return 0;
107 }
108 
109 
110 static int wpa_supplicant_ctrl_iface_detach(struct wpa_ctrl_dst **head,
111 #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
112 					    struct sockaddr_in6 *from,
113 #else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
114 					    struct sockaddr_in *from,
115 #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
116 					    socklen_t fromlen)
117 {
118 	struct wpa_ctrl_dst *dst, *prev = NULL;
119 #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
120 	char addr[INET6_ADDRSTRLEN];
121 #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
122 
123 	dst = *head;
124 	while (dst) {
125 #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
126 		if (from->sin6_port == dst->addr.sin6_port &&
127 		    !os_memcmp(&from->sin6_addr, &dst->addr.sin6_addr,
128 			       sizeof(from->sin6_addr))) {
129 			wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor detached %s:%d",
130 				   inet_ntop(AF_INET6, &from->sin6_addr, addr,
131 					     sizeof(*from)),
132 				   ntohs(from->sin6_port));
133 #else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
134 		if (from->sin_addr.s_addr == dst->addr.sin_addr.s_addr &&
135 		    from->sin_port == dst->addr.sin_port) {
136 			wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor detached "
137 				   "%s:%d", inet_ntoa(from->sin_addr),
138 				   ntohs(from->sin_port));
139 #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
140 			if (prev == NULL)
141 				*head = dst->next;
142 			else
143 				prev->next = dst->next;
144 			os_free(dst);
145 			return 0;
146 		}
147 		prev = dst;
148 		dst = dst->next;
149 	}
150 	return -1;
151 }
152 
153 
154 static int wpa_supplicant_ctrl_iface_level(struct ctrl_iface_priv *priv,
155 #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
156 					   struct sockaddr_in6 *from,
157 #else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
158 					   struct sockaddr_in *from,
159 #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
160 					   socklen_t fromlen,
161 					   char *level)
162 {
163 	struct wpa_ctrl_dst *dst;
164 #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
165 	char addr[INET6_ADDRSTRLEN];
166 #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
167 
168 	wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", level);
169 
170 	dst = priv->ctrl_dst;
171 	while (dst) {
172 #if CONFIG_CTRL_IFACE_UDP_IPV6
173 		if (from->sin6_port == dst->addr.sin6_port &&
174 		    !os_memcmp(&from->sin6_addr, &dst->addr.sin6_addr,
175 			       sizeof(from->sin6_addr))) {
176 			wpa_printf(MSG_DEBUG, "CTRL_IFACE changed monitor level %s:%d",
177 				   inet_ntop(AF_INET6, &from->sin6_addr, addr,
178 					     sizeof(*from)),
179 				   ntohs(from->sin6_port));
180 #else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
181 		if (from->sin_addr.s_addr == dst->addr.sin_addr.s_addr &&
182 		    from->sin_port == dst->addr.sin_port) {
183 			wpa_printf(MSG_DEBUG, "CTRL_IFACE changed monitor "
184 				   "level %s:%d", inet_ntoa(from->sin_addr),
185 				   ntohs(from->sin_port));
186 #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
187 			dst->debug_level = atoi(level);
188 			return 0;
189 		}
190 		dst = dst->next;
191 	}
192 
193 	return -1;
194 }
195 
196 
197 static char *
198 wpa_supplicant_ctrl_iface_get_cookie(struct ctrl_iface_priv *priv,
199 				     size_t *reply_len)
200 {
201 	char *reply;
202 	reply = os_malloc(7 + 2 * COOKIE_LEN + 1);
203 	if (reply == NULL) {
204 		*reply_len = 1;
205 		return NULL;
206 	}
207 
208 	os_memcpy(reply, "COOKIE=", 7);
209 	wpa_snprintf_hex(reply + 7, 2 * COOKIE_LEN + 1,
210 			 priv->cookie, COOKIE_LEN);
211 
212 	*reply_len = 7 + 2 * COOKIE_LEN;
213 	return reply;
214 }
215 
216 
217 static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx,
218 					      void *sock_ctx)
219 {
220 	struct wpa_supplicant *wpa_s = eloop_ctx;
221 	struct ctrl_iface_priv *priv = sock_ctx;
222 	char *buf, *pos;
223 	int res;
224 #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
225 	struct sockaddr_in6 from;
226 #ifndef CONFIG_CTRL_IFACE_UDP_REMOTE
227 	char addr[INET6_ADDRSTRLEN];
228 #endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
229 #else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
230 	struct sockaddr_in from;
231 #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
232 	socklen_t fromlen = sizeof(from);
233 	char *reply = NULL;
234 	size_t reply_len = 0;
235 	int new_attached = 0;
236 	u8 cookie[COOKIE_LEN];
237 
238 	buf = os_malloc(CTRL_IFACE_MAX_LEN + 1);
239 	if (!buf)
240 		return;
241 	res = recvfrom(sock, buf, CTRL_IFACE_MAX_LEN, 0,
242 		       (struct sockaddr *) &from, &fromlen);
243 	if (res < 0) {
244 		wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s",
245 			   strerror(errno));
246 		os_free(buf);
247 		return;
248 	}
249 
250 #ifndef CONFIG_CTRL_IFACE_UDP_REMOTE
251 #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
252 	inet_ntop(AF_INET6, &from.sin6_addr, addr, sizeof(from));
253 	if (os_strcmp(addr, "::1")) {
254 		wpa_printf(MSG_DEBUG, "CTRL: Drop packet from unexpected source %s",
255 			   addr);
256 		os_free(buf);
257 		return;
258 	}
259 #else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
260 	if (from.sin_addr.s_addr != htonl((127 << 24) | 1)) {
261 		/*
262 		 * The OS networking stack is expected to drop this kind of
263 		 * frames since the socket is bound to only localhost address.
264 		 * Just in case, drop the frame if it is coming from any other
265 		 * address.
266 		 */
267 		wpa_printf(MSG_DEBUG, "CTRL: Drop packet from unexpected "
268 			   "source %s", inet_ntoa(from.sin_addr));
269 		os_free(buf);
270 		return;
271 	}
272 #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
273 #endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
274 
275 	if ((size_t) res > CTRL_IFACE_MAX_LEN) {
276 		wpa_printf(MSG_ERROR, "recvform(ctrl_iface): input truncated");
277 		os_free(buf);
278 		return;
279 	}
280 	buf[res] = '\0';
281 
282 	if (os_strcmp(buf, "GET_COOKIE") == 0) {
283 		reply = wpa_supplicant_ctrl_iface_get_cookie(priv, &reply_len);
284 		goto done;
285 	}
286 
287 	/*
288 	 * Require that the client includes a prefix with the 'cookie' value
289 	 * fetched with GET_COOKIE command. This is used to verify that the
290 	 * client has access to a bidirectional link over UDP in order to
291 	 * avoid attacks using forged localhost IP address even if the OS does
292 	 * not block such frames from remote destinations.
293 	 */
294 	if (os_strncmp(buf, "COOKIE=", 7) != 0) {
295 		wpa_printf(MSG_DEBUG, "CTLR: No cookie in the request - "
296 			   "drop request");
297 		os_free(buf);
298 		return;
299 	}
300 
301 	if (hexstr2bin(buf + 7, cookie, COOKIE_LEN) < 0) {
302 		wpa_printf(MSG_DEBUG, "CTLR: Invalid cookie format in the "
303 			   "request - drop request");
304 		os_free(buf);
305 		return;
306 	}
307 
308 	if (os_memcmp(cookie, priv->cookie, COOKIE_LEN) != 0) {
309 		wpa_printf(MSG_DEBUG, "CTLR: Invalid cookie in the request - "
310 			   "drop request");
311 		os_free(buf);
312 		return;
313 	}
314 
315 	pos = buf + 7 + 2 * COOKIE_LEN;
316 	while (*pos == ' ')
317 		pos++;
318 
319 	if (os_strcmp(pos, "ATTACH") == 0) {
320 		if (wpa_supplicant_ctrl_iface_attach(&priv->ctrl_dst,
321 						     &from, fromlen))
322 			reply_len = 1;
323 		else {
324 			new_attached = 1;
325 			reply_len = 2;
326 		}
327 	} else if (os_strcmp(pos, "DETACH") == 0) {
328 		if (wpa_supplicant_ctrl_iface_detach(&priv->ctrl_dst,
329 						     &from, fromlen))
330 			reply_len = 1;
331 		else
332 			reply_len = 2;
333 	} else if (os_strncmp(pos, "LEVEL ", 6) == 0) {
334 		if (wpa_supplicant_ctrl_iface_level(priv, &from, fromlen,
335 						    pos + 6))
336 			reply_len = 1;
337 		else
338 			reply_len = 2;
339 	} else {
340 		reply = wpa_supplicant_ctrl_iface_process(wpa_s, pos,
341 							  &reply_len);
342 	}
343 
344  done:
345 	if (reply) {
346 		sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,
347 		       fromlen);
348 		os_free(reply);
349 	} else if (reply_len == 1) {
350 		sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
351 		       fromlen);
352 	} else if (reply_len == 2) {
353 		sendto(sock, "OK\n", 3, 0, (struct sockaddr *) &from,
354 		       fromlen);
355 	}
356 
357 	os_free(buf);
358 
359 	if (new_attached)
360 		eapol_sm_notify_ctrl_attached(wpa_s->eapol);
361 }
362 
363 
364 static void wpa_supplicant_ctrl_iface_msg_cb(void *ctx, int level,
365 					     enum wpa_msg_type type,
366 					     const char *txt, size_t len)
367 {
368 	struct wpa_supplicant *wpa_s = ctx;
369 
370 	if (!wpa_s)
371 		return;
372 
373 	if (type != WPA_MSG_NO_GLOBAL && wpa_s->global->ctrl_iface) {
374 		struct ctrl_iface_global_priv *priv = wpa_s->global->ctrl_iface;
375 
376 		if (priv->ctrl_dst) {
377 			wpa_supplicant_ctrl_iface_send(
378 				wpa_s,
379 				type != WPA_MSG_PER_INTERFACE ?
380 				NULL : wpa_s->ifname,
381 				priv->sock, &priv->ctrl_dst, level, txt, len);
382 		}
383 	}
384 
385 	if (type == WPA_MSG_ONLY_GLOBAL || !wpa_s->ctrl_iface)
386 		return;
387 
388 	wpa_supplicant_ctrl_iface_send(wpa_s, NULL, wpa_s->ctrl_iface->sock,
389 				       &wpa_s->ctrl_iface->ctrl_dst,
390 				       level, txt, len);
391 }
392 
393 
394 struct ctrl_iface_priv *
395 wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
396 {
397 	struct ctrl_iface_priv *priv;
398 	char port_str[40];
399 	int port = WPA_CTRL_IFACE_PORT;
400 	char *pos;
401 #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
402 	struct sockaddr_in6 addr;
403 	int domain = PF_INET6;
404 #else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
405 	struct sockaddr_in addr;
406 	int domain = PF_INET;
407 #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
408 
409 	priv = os_zalloc(sizeof(*priv));
410 	if (priv == NULL)
411 		return NULL;
412 	priv->wpa_s = wpa_s;
413 	priv->sock = -1;
414 	os_get_random(priv->cookie, COOKIE_LEN);
415 
416 	if (wpa_s->conf->ctrl_interface == NULL)
417 		return priv;
418 
419 	pos = os_strstr(wpa_s->conf->ctrl_interface, "udp:");
420 	if (pos) {
421 		pos += 4;
422 		port = atoi(pos);
423 		if (port <= 0) {
424 			wpa_printf(MSG_ERROR, "Invalid ctrl_iface UDP port: %s",
425 				   wpa_s->conf->ctrl_interface);
426 			goto fail;
427 		}
428 	}
429 
430 	priv->sock = socket(domain, SOCK_DGRAM, 0);
431 	if (priv->sock < 0) {
432 		wpa_printf(MSG_ERROR, "socket(PF_INET): %s", strerror(errno));
433 		goto fail;
434 	}
435 
436 	os_memset(&addr, 0, sizeof(addr));
437 #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
438 	addr.sin6_family = AF_INET6;
439 #ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
440 	addr.sin6_addr = in6addr_any;
441 #else /* CONFIG_CTRL_IFACE_UDP_REMOTE */
442 	inet_pton(AF_INET6, "::1", &addr.sin6_addr);
443 #endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
444 #else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
445 	addr.sin_family = AF_INET;
446 #ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
447 	addr.sin_addr.s_addr = INADDR_ANY;
448 #else /* CONFIG_CTRL_IFACE_UDP_REMOTE */
449 	addr.sin_addr.s_addr = htonl((127 << 24) | 1);
450 #endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
451 #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
452 try_again:
453 #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
454 	addr.sin6_port = htons(port);
455 #else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
456 	addr.sin_port = htons(port);
457 #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
458 	if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
459 		port--;
460 		if ((WPA_CTRL_IFACE_PORT - port) < WPA_CTRL_IFACE_PORT_LIMIT)
461 			goto try_again;
462 		wpa_printf(MSG_ERROR, "bind(AF_INET): %s", strerror(errno));
463 		goto fail;
464 	}
465 
466 	/* Update the ctrl_interface value to match the selected port */
467 	os_snprintf(port_str, sizeof(port_str), "udp:%d", port);
468 	os_free(wpa_s->conf->ctrl_interface);
469 	wpa_s->conf->ctrl_interface = os_strdup(port_str);
470 	if (!wpa_s->conf->ctrl_interface) {
471 		wpa_msg(wpa_s, MSG_ERROR, "Failed to malloc ctrl_interface");
472 		goto fail;
473 	}
474 
475 #ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
476 	wpa_msg(wpa_s, MSG_DEBUG, "ctrl_iface_init UDP port: %d", port);
477 #endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
478 
479 	eloop_register_read_sock(priv->sock, wpa_supplicant_ctrl_iface_receive,
480 				 wpa_s, priv);
481 	wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb);
482 
483 	return priv;
484 
485 fail:
486 	if (priv->sock >= 0)
487 		close(priv->sock);
488 	os_free(priv);
489 	return NULL;
490 }
491 
492 
493 void wpa_supplicant_ctrl_iface_deinit(struct wpa_supplicant *wpa_s,
494 				      struct ctrl_iface_priv *priv)
495 {
496 	if (!priv)
497 		return;
498 
499 	if (priv->sock > -1) {
500 		eloop_unregister_read_sock(priv->sock);
501 		if (priv->ctrl_dst) {
502 			/*
503 			 * Wait before closing the control socket if
504 			 * there are any attached monitors in order to allow
505 			 * them to receive any pending messages.
506 			 */
507 			wpa_printf(MSG_DEBUG, "CTRL_IFACE wait for attached "
508 				   "monitors to receive messages");
509 			os_sleep(0, 100000);
510 		}
511 		close(priv->sock);
512 		priv->sock = -1;
513 	}
514 
515 	wpas_ctrl_iface_free_dst(priv->ctrl_dst);
516 	os_free(priv);
517 }
518 
519 
520 static void wpa_supplicant_ctrl_iface_send(struct wpa_supplicant *wpa_s,
521 					   const char *ifname, int sock,
522 					   struct wpa_ctrl_dst **head,
523 					   int level, const char *buf,
524 					   size_t len)
525 {
526 	struct wpa_ctrl_dst *dst, *next;
527 	char levelstr[64];
528 	int idx;
529 	char *sbuf;
530 	int llen;
531 #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
532 	char addr[INET6_ADDRSTRLEN];
533 #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
534 
535 	dst = *head;
536 	if (sock < 0 || dst == NULL)
537 		return;
538 
539 	if (ifname)
540 		os_snprintf(levelstr, sizeof(levelstr), "IFNAME=%s <%d>",
541 			    ifname, level);
542 	else
543 		os_snprintf(levelstr, sizeof(levelstr), "<%d>", level);
544 
545 	llen = os_strlen(levelstr);
546 	sbuf = os_malloc(llen + len);
547 	if (sbuf == NULL)
548 		return;
549 
550 	os_memcpy(sbuf, levelstr, llen);
551 	os_memcpy(sbuf + llen, buf, len);
552 
553 	idx = 0;
554 	while (dst) {
555 		next = dst->next;
556 		if (level >= dst->debug_level) {
557 #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
558 			wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor send %s:%d",
559 				   inet_ntop(AF_INET6, &dst->addr.sin6_addr,
560 					     addr, sizeof(dst->addr)),
561 				   ntohs(dst->addr.sin6_port));
562 #else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
563 			wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor send %s:%d",
564 				   inet_ntoa(dst->addr.sin_addr),
565 				   ntohs(dst->addr.sin_port));
566 #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
567 			if (sendto(sock, sbuf, llen + len, 0,
568 				   (struct sockaddr *) &dst->addr,
569 				   sizeof(dst->addr)) < 0) {
570 				wpa_printf(MSG_ERROR,
571 					   "sendto(CTRL_IFACE monitor): %s",
572 					   strerror(errno));
573 				dst->errors++;
574 				if (dst->errors > 10) {
575 					wpa_supplicant_ctrl_iface_detach(
576 						head, &dst->addr,
577 						dst->addrlen);
578 				}
579 			} else
580 				dst->errors = 0;
581 		}
582 		idx++;
583 		dst = next;
584 	}
585 	os_free(sbuf);
586 }
587 
588 
589 void wpa_supplicant_ctrl_iface_wait(struct ctrl_iface_priv *priv)
590 {
591 	wpa_printf(MSG_DEBUG, "CTRL_IFACE - %s - wait for monitor",
592 		   priv->wpa_s->ifname);
593 	eloop_wait_for_read_sock(priv->sock);
594 }
595 
596 
597 /* Global ctrl_iface */
598 
599 static char *
600 wpa_supplicant_global_get_cookie(struct ctrl_iface_global_priv *priv,
601 				 size_t *reply_len)
602 {
603 	char *reply;
604 	reply = os_malloc(7 + 2 * COOKIE_LEN + 1);
605 	if (reply == NULL) {
606 		*reply_len = 1;
607 		return NULL;
608 	}
609 
610 	os_memcpy(reply, "COOKIE=", 7);
611 	wpa_snprintf_hex(reply + 7, 2 * COOKIE_LEN + 1,
612 			 priv->cookie, COOKIE_LEN);
613 
614 	*reply_len = 7 + 2 * COOKIE_LEN;
615 	return reply;
616 }
617 
618 
619 static void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx,
620 						     void *sock_ctx)
621 {
622 	struct wpa_global *global = eloop_ctx;
623 	struct ctrl_iface_global_priv *priv = sock_ctx;
624 	char *buf, *pos;
625 	int res;
626 #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
627 	struct sockaddr_in6 from;
628 #ifndef CONFIG_CTRL_IFACE_UDP_REMOTE
629 	char addr[INET6_ADDRSTRLEN];
630 #endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
631 #else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
632 	struct sockaddr_in from;
633 #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
634 	socklen_t fromlen = sizeof(from);
635 	char *reply = NULL;
636 	size_t reply_len;
637 	u8 cookie[COOKIE_LEN];
638 
639 	buf = os_malloc(CTRL_IFACE_MAX_LEN + 1);
640 	if (!buf)
641 		return;
642 	res = recvfrom(sock, buf, CTRL_IFACE_MAX_LEN, 0,
643 		       (struct sockaddr *) &from, &fromlen);
644 	if (res < 0) {
645 		wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s",
646 			   strerror(errno));
647 		os_free(buf);
648 		return;
649 	}
650 
651 #ifndef CONFIG_CTRL_IFACE_UDP_REMOTE
652 #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
653 	inet_ntop(AF_INET6, &from.sin6_addr, addr, sizeof(from));
654 	if (os_strcmp(addr, "::1")) {
655 		wpa_printf(MSG_DEBUG, "CTRL: Drop packet from unexpected source %s",
656 			   addr);
657 		os_free(buf);
658 		return;
659 	}
660 #else /* CONFIG_CTRL_IFACE_UDP_IPV6 */
661 	if (from.sin_addr.s_addr != htonl((127 << 24) | 1)) {
662 		/*
663 		 * The OS networking stack is expected to drop this kind of
664 		 * frames since the socket is bound to only localhost address.
665 		 * Just in case, drop the frame if it is coming from any other
666 		 * address.
667 		 */
668 		wpa_printf(MSG_DEBUG, "CTRL: Drop packet from unexpected "
669 			   "source %s", inet_ntoa(from.sin_addr));
670 		os_free(buf);
671 		return;
672 	}
673 #endif /* CONFIG_CTRL_IFACE_UDP_IPV6 */
674 #endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
675 
676 	if ((size_t) res > CTRL_IFACE_MAX_LEN) {
677 		wpa_printf(MSG_ERROR, "recvform(ctrl_iface): input truncated");
678 		os_free(buf);
679 		return;
680 	}
681 	buf[res] = '\0';
682 
683 	if (os_strcmp(buf, "GET_COOKIE") == 0) {
684 		reply = wpa_supplicant_global_get_cookie(priv, &reply_len);
685 		goto done;
686 	}
687 
688 	if (os_strncmp(buf, "COOKIE=", 7) != 0) {
689 		wpa_printf(MSG_DEBUG, "CTLR: No cookie in the request - "
690 			   "drop request");
691 		os_free(buf);
692 		return;
693 	}
694 
695 	if (hexstr2bin(buf + 7, cookie, COOKIE_LEN) < 0) {
696 		wpa_printf(MSG_DEBUG, "CTLR: Invalid cookie format in the "
697 			   "request - drop request");
698 		os_free(buf);
699 		return;
700 	}
701 
702 	if (os_memcmp(cookie, priv->cookie, COOKIE_LEN) != 0) {
703 		wpa_printf(MSG_DEBUG, "CTLR: Invalid cookie in the request - "
704 			   "drop request");
705 		os_free(buf);
706 		return;
707 	}
708 
709 	pos = buf + 7 + 2 * COOKIE_LEN;
710 	while (*pos == ' ')
711 		pos++;
712 
713 	if (os_strcmp(pos, "ATTACH") == 0) {
714 		if (wpa_supplicant_ctrl_iface_attach(&priv->ctrl_dst,
715 						     &from, fromlen))
716 			reply_len = 1;
717 		else
718 			reply_len = 2;
719 	} else if (os_strcmp(pos, "DETACH") == 0) {
720 		if (wpa_supplicant_ctrl_iface_detach(&priv->ctrl_dst,
721 						     &from, fromlen))
722 			reply_len = 1;
723 		else
724 			reply_len = 2;
725 	} else {
726 		reply = wpa_supplicant_global_ctrl_iface_process(global, pos,
727 								 &reply_len);
728 	}
729 
730  done:
731 	if (reply) {
732 		sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,
733 		       fromlen);
734 		os_free(reply);
735 	} else if (reply_len == 1) {
736 		sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
737 		       fromlen);
738 	} else if (reply_len == 2) {
739 		sendto(sock, "OK\n", 3, 0, (struct sockaddr *) &from,
740 		       fromlen);
741 	}
742 
743 	os_free(buf);
744 }
745 
746 
747 struct ctrl_iface_global_priv *
748 wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global)
749 {
750 	struct ctrl_iface_global_priv *priv;
751 	struct sockaddr_in addr;
752 	char *pos;
753 	int port = WPA_GLOBAL_CTRL_IFACE_PORT;
754 
755 	priv = os_zalloc(sizeof(*priv));
756 	if (priv == NULL)
757 		return NULL;
758 	priv->sock = -1;
759 	os_get_random(priv->cookie, COOKIE_LEN);
760 
761 	if (global->params.ctrl_interface == NULL)
762 		return priv;
763 
764 	wpa_printf(MSG_DEBUG, "Global control interface '%s'",
765 		   global->params.ctrl_interface);
766 
767 	pos = os_strstr(global->params.ctrl_interface, "udp:");
768 	if (pos) {
769 		pos += 4;
770 		port = atoi(pos);
771 		if (port <= 0) {
772 			wpa_printf(MSG_ERROR, "Invalid global ctrl UDP port %s",
773 				   global->params.ctrl_interface);
774 			goto fail;
775 		}
776 	}
777 
778 	priv->sock = socket(PF_INET, SOCK_DGRAM, 0);
779 	if (priv->sock < 0) {
780 		wpa_printf(MSG_ERROR, "socket(PF_INET): %s", strerror(errno));
781 		goto fail;
782 	}
783 
784 	os_memset(&addr, 0, sizeof(addr));
785 	addr.sin_family = AF_INET;
786 #ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
787 	addr.sin_addr.s_addr = INADDR_ANY;
788 #else /* CONFIG_CTRL_IFACE_UDP_REMOTE */
789 	addr.sin_addr.s_addr = htonl((127 << 24) | 1);
790 #endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
791 try_again:
792 	addr.sin_port = htons(port);
793 	if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
794 		port++;
795 		if ((port - WPA_GLOBAL_CTRL_IFACE_PORT) <
796 		    WPA_GLOBAL_CTRL_IFACE_PORT_LIMIT && !pos)
797 			goto try_again;
798 		wpa_printf(MSG_ERROR, "bind(AF_INET): %s", strerror(errno));
799 		goto fail;
800 	}
801 
802 #ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
803 	wpa_printf(MSG_DEBUG, "global_ctrl_iface_init UDP port: %d", port);
804 #endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
805 
806 	eloop_register_read_sock(priv->sock,
807 				 wpa_supplicant_global_ctrl_iface_receive,
808 				 global, priv);
809 	wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb);
810 
811 	return priv;
812 
813 fail:
814 	if (priv->sock >= 0)
815 		close(priv->sock);
816 	os_free(priv);
817 	return NULL;
818 }
819 
820 
821 void
822 wpa_supplicant_global_ctrl_iface_deinit(struct ctrl_iface_global_priv *priv)
823 {
824 	if (priv->sock >= 0) {
825 		eloop_unregister_read_sock(priv->sock);
826 		close(priv->sock);
827 	}
828 
829 	wpas_ctrl_iface_free_dst(priv->ctrl_dst);
830 	os_free(priv);
831 }
832