1 /* 2 * WPA Supplicant / UDP socket -based control interface 3 * Copyright (c) 2004-2005, Jouni Malinen <j (at) 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 struct sockaddr_in addr; 34 socklen_t addrlen; 35 int debug_level; 36 int errors; 37 }; 38 39 40 struct ctrl_iface_priv { 41 struct wpa_supplicant *wpa_s; 42 int sock; 43 struct wpa_ctrl_dst *ctrl_dst; 44 u8 cookie[COOKIE_LEN]; 45 }; 46 47 48 static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv, 49 int level, const char *buf, 50 size_t len); 51 52 53 static int wpa_supplicant_ctrl_iface_attach(struct ctrl_iface_priv *priv, 54 struct sockaddr_in *from, 55 socklen_t fromlen) 56 { 57 struct wpa_ctrl_dst *dst; 58 59 dst = os_zalloc(sizeof(*dst)); 60 if (dst == NULL) 61 return -1; 62 os_memcpy(&dst->addr, from, sizeof(struct sockaddr_in)); 63 dst->addrlen = fromlen; 64 dst->debug_level = MSG_INFO; 65 dst->next = priv->ctrl_dst; 66 priv->ctrl_dst = dst; 67 wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor attached %s:%d", 68 inet_ntoa(from->sin_addr), ntohs(from->sin_port)); 69 return 0; 70 } 71 72 73 static int wpa_supplicant_ctrl_iface_detach(struct ctrl_iface_priv *priv, 74 struct sockaddr_in *from, 75 socklen_t fromlen) 76 { 77 struct wpa_ctrl_dst *dst, *prev = NULL; 78 79 dst = priv->ctrl_dst; 80 while (dst) { 81 if (from->sin_addr.s_addr == dst->addr.sin_addr.s_addr && 82 from->sin_port == dst->addr.sin_port) { 83 wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor detached " 84 "%s:%d", inet_ntoa(from->sin_addr), 85 ntohs(from->sin_port)); 86 if (prev == NULL) 87 priv->ctrl_dst = dst->next; 88 else 89 prev->next = dst->next; 90 os_free(dst); 91 return 0; 92 } 93 prev = dst; 94 dst = dst->next; 95 } 96 return -1; 97 } 98 99 100 static int wpa_supplicant_ctrl_iface_level(struct ctrl_iface_priv *priv, 101 struct sockaddr_in *from, 102 socklen_t fromlen, 103 char *level) 104 { 105 struct wpa_ctrl_dst *dst; 106 107 wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", level); 108 109 dst = priv->ctrl_dst; 110 while (dst) { 111 if (from->sin_addr.s_addr == dst->addr.sin_addr.s_addr && 112 from->sin_port == dst->addr.sin_port) { 113 wpa_printf(MSG_DEBUG, "CTRL_IFACE changed monitor " 114 "level %s:%d", inet_ntoa(from->sin_addr), 115 ntohs(from->sin_port)); 116 dst->debug_level = atoi(level); 117 return 0; 118 } 119 dst = dst->next; 120 } 121 122 return -1; 123 } 124 125 126 static char * 127 wpa_supplicant_ctrl_iface_get_cookie(struct ctrl_iface_priv *priv, 128 size_t *reply_len) 129 { 130 char *reply; 131 reply = os_malloc(7 + 2 * COOKIE_LEN + 1); 132 if (reply == NULL) { 133 *reply_len = 1; 134 return NULL; 135 } 136 137 os_memcpy(reply, "COOKIE=", 7); 138 wpa_snprintf_hex(reply + 7, 2 * COOKIE_LEN + 1, 139 priv->cookie, COOKIE_LEN); 140 141 *reply_len = 7 + 2 * COOKIE_LEN; 142 return reply; 143 } 144 145 146 static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx, 147 void *sock_ctx) 148 { 149 struct wpa_supplicant *wpa_s = eloop_ctx; 150 struct ctrl_iface_priv *priv = sock_ctx; 151 char buf[256], *pos; 152 int res; 153 struct sockaddr_in from; 154 socklen_t fromlen = sizeof(from); 155 char *reply = NULL; 156 size_t reply_len = 0; 157 int new_attached = 0; 158 u8 cookie[COOKIE_LEN]; 159 160 res = recvfrom(sock, buf, sizeof(buf) - 1, 0, 161 (struct sockaddr *) &from, &fromlen); 162 if (res < 0) { 163 perror("recvfrom(ctrl_iface)"); 164 return; 165 } 166 167 #ifndef CONFIG_CTRL_IFACE_UDP_REMOTE 168 if (from.sin_addr.s_addr != htonl((127 << 24) | 1)) { 169 /* 170 * The OS networking stack is expected to drop this kind of 171 * frames since the socket is bound to only localhost address. 172 * Just in case, drop the frame if it is coming from any other 173 * address. 174 */ 175 wpa_printf(MSG_DEBUG, "CTRL: Drop packet from unexpected " 176 "source %s", inet_ntoa(from.sin_addr)); 177 return; 178 } 179 #endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */ 180 181 buf[res] = '\0'; 182 183 if (os_strcmp(buf, "GET_COOKIE") == 0) { 184 reply = wpa_supplicant_ctrl_iface_get_cookie(priv, &reply_len); 185 goto done; 186 } 187 188 /* 189 * Require that the client includes a prefix with the 'cookie' value 190 * fetched with GET_COOKIE command. This is used to verify that the 191 * client has access to a bidirectional link over UDP in order to 192 * avoid attacks using forged localhost IP address even if the OS does 193 * not block such frames from remote destinations. 194 */ 195 if (os_strncmp(buf, "COOKIE=", 7) != 0) { 196 wpa_printf(MSG_DEBUG, "CTLR: No cookie in the request - " 197 "drop request"); 198 return; 199 } 200 201 if (hexstr2bin(buf + 7, cookie, COOKIE_LEN) < 0) { 202 wpa_printf(MSG_DEBUG, "CTLR: Invalid cookie format in the " 203 "request - drop request"); 204 return; 205 } 206 207 if (os_memcmp(cookie, priv->cookie, COOKIE_LEN) != 0) { 208 wpa_printf(MSG_DEBUG, "CTLR: Invalid cookie in the request - " 209 "drop request"); 210 return; 211 } 212 213 pos = buf + 7 + 2 * COOKIE_LEN; 214 while (*pos == ' ') 215 pos++; 216 217 if (os_strcmp(pos, "ATTACH") == 0) { 218 if (wpa_supplicant_ctrl_iface_attach(priv, &from, fromlen)) 219 reply_len = 1; 220 else { 221 new_attached = 1; 222 reply_len = 2; 223 } 224 } else if (os_strcmp(pos, "DETACH") == 0) { 225 if (wpa_supplicant_ctrl_iface_detach(priv, &from, fromlen)) 226 reply_len = 1; 227 else 228 reply_len = 2; 229 } else if (os_strncmp(pos, "LEVEL ", 6) == 0) { 230 if (wpa_supplicant_ctrl_iface_level(priv, &from, fromlen, 231 pos + 6)) 232 reply_len = 1; 233 else 234 reply_len = 2; 235 } else { 236 reply = wpa_supplicant_ctrl_iface_process(wpa_s, pos, 237 &reply_len); 238 } 239 240 done: 241 if (reply) { 242 sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, 243 fromlen); 244 os_free(reply); 245 } else if (reply_len == 1) { 246 sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from, 247 fromlen); 248 } else if (reply_len == 2) { 249 sendto(sock, "OK\n", 3, 0, (struct sockaddr *) &from, 250 fromlen); 251 } 252 253 if (new_attached) 254 eapol_sm_notify_ctrl_attached(wpa_s->eapol); 255 } 256 257 258 static void wpa_supplicant_ctrl_iface_msg_cb(void *ctx, int level, int global, 259 const char *txt, size_t len) 260 { 261 struct wpa_supplicant *wpa_s = ctx; 262 if (wpa_s == NULL || wpa_s->ctrl_iface == NULL) 263 return; 264 wpa_supplicant_ctrl_iface_send(wpa_s->ctrl_iface, level, txt, len); 265 } 266 267 268 struct ctrl_iface_priv * 269 wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s) 270 { 271 struct ctrl_iface_priv *priv; 272 struct sockaddr_in addr; 273 int port = WPA_CTRL_IFACE_PORT; 274 275 priv = os_zalloc(sizeof(*priv)); 276 if (priv == NULL) 277 return NULL; 278 priv->wpa_s = wpa_s; 279 priv->sock = -1; 280 os_get_random(priv->cookie, COOKIE_LEN); 281 282 if (wpa_s->conf->ctrl_interface == NULL) 283 return priv; 284 285 priv->sock = socket(PF_INET, SOCK_DGRAM, 0); 286 if (priv->sock < 0) { 287 perror("socket(PF_INET)"); 288 goto fail; 289 } 290 291 os_memset(&addr, 0, sizeof(addr)); 292 addr.sin_family = AF_INET; 293 #ifdef CONFIG_CTRL_IFACE_UDP_REMOTE 294 addr.sin_addr.s_addr = INADDR_ANY; 295 #else /* CONFIG_CTRL_IFACE_UDP_REMOTE */ 296 addr.sin_addr.s_addr = htonl((127 << 24) | 1); 297 #endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */ 298 try_again: 299 addr.sin_port = htons(port); 300 if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { 301 port--; 302 if ((WPA_CTRL_IFACE_PORT - port) < WPA_CTRL_IFACE_PORT_LIMIT) 303 goto try_again; 304 perror("bind(AF_INET)"); 305 goto fail; 306 } 307 308 #ifdef CONFIG_CTRL_IFACE_UDP_REMOTE 309 wpa_msg(wpa_s, MSG_DEBUG, "ctrl_iface_init UDP port: %d", port); 310 #endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */ 311 312 eloop_register_read_sock(priv->sock, wpa_supplicant_ctrl_iface_receive, 313 wpa_s, priv); 314 wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb); 315 316 return priv; 317 318 fail: 319 if (priv->sock >= 0) 320 close(priv->sock); 321 os_free(priv); 322 return NULL; 323 } 324 325 326 void wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv) 327 { 328 struct wpa_ctrl_dst *dst, *prev; 329 330 if (priv->sock > -1) { 331 eloop_unregister_read_sock(priv->sock); 332 if (priv->ctrl_dst) { 333 /* 334 * Wait before closing the control socket if 335 * there are any attached monitors in order to allow 336 * them to receive any pending messages. 337 */ 338 wpa_printf(MSG_DEBUG, "CTRL_IFACE wait for attached " 339 "monitors to receive messages"); 340 os_sleep(0, 100000); 341 } 342 close(priv->sock); 343 priv->sock = -1; 344 } 345 346 dst = priv->ctrl_dst; 347 while (dst) { 348 prev = dst; 349 dst = dst->next; 350 os_free(prev); 351 } 352 os_free(priv); 353 } 354 355 356 static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv, 357 int level, const char *buf, 358 size_t len) 359 { 360 struct wpa_ctrl_dst *dst, *next; 361 char levelstr[10]; 362 int idx; 363 char *sbuf; 364 int llen; 365 366 dst = priv->ctrl_dst; 367 if (priv->sock < 0 || dst == NULL) 368 return; 369 370 os_snprintf(levelstr, sizeof(levelstr), "<%d>", level); 371 372 llen = os_strlen(levelstr); 373 sbuf = os_malloc(llen + len); 374 if (sbuf == NULL) 375 return; 376 377 os_memcpy(sbuf, levelstr, llen); 378 os_memcpy(sbuf + llen, buf, len); 379 380 idx = 0; 381 while (dst) { 382 next = dst->next; 383 if (level >= dst->debug_level) { 384 wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor send %s:%d", 385 inet_ntoa(dst->addr.sin_addr), 386 ntohs(dst->addr.sin_port)); 387 if (sendto(priv->sock, sbuf, llen + len, 0, 388 (struct sockaddr *) &dst->addr, 389 sizeof(dst->addr)) < 0) { 390 perror("sendto(CTRL_IFACE monitor)"); 391 dst->errors++; 392 if (dst->errors > 10) { 393 wpa_supplicant_ctrl_iface_detach( 394 priv, &dst->addr, 395 dst->addrlen); 396 } 397 } else 398 dst->errors = 0; 399 } 400 idx++; 401 dst = next; 402 } 403 os_free(sbuf); 404 } 405 406 407 void wpa_supplicant_ctrl_iface_wait(struct ctrl_iface_priv *priv) 408 { 409 wpa_printf(MSG_DEBUG, "CTRL_IFACE - %s - wait for monitor", 410 priv->wpa_s->ifname); 411 eloop_wait_for_read_sock(priv->sock); 412 } 413 414 415 /* Global ctrl_iface */ 416 417 struct ctrl_iface_global_priv { 418 int sock; 419 u8 cookie[COOKIE_LEN]; 420 }; 421 422 423 static char * 424 wpa_supplicant_global_get_cookie(struct ctrl_iface_global_priv *priv, 425 size_t *reply_len) 426 { 427 char *reply; 428 reply = os_malloc(7 + 2 * COOKIE_LEN + 1); 429 if (reply == NULL) { 430 *reply_len = 1; 431 return NULL; 432 } 433 434 os_memcpy(reply, "COOKIE=", 7); 435 wpa_snprintf_hex(reply + 7, 2 * COOKIE_LEN + 1, 436 priv->cookie, COOKIE_LEN); 437 438 *reply_len = 7 + 2 * COOKIE_LEN; 439 return reply; 440 } 441 442 443 static void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx, 444 void *sock_ctx) 445 { 446 struct wpa_global *global = eloop_ctx; 447 struct ctrl_iface_global_priv *priv = sock_ctx; 448 char buf[256], *pos; 449 int res; 450 struct sockaddr_in from; 451 socklen_t fromlen = sizeof(from); 452 char *reply; 453 size_t reply_len; 454 u8 cookie[COOKIE_LEN]; 455 456 res = recvfrom(sock, buf, sizeof(buf) - 1, 0, 457 (struct sockaddr *) &from, &fromlen); 458 if (res < 0) { 459 perror("recvfrom(ctrl_iface)"); 460 return; 461 } 462 463 #ifndef CONFIG_CTRL_IFACE_UDP_REMOTE 464 if (from.sin_addr.s_addr != htonl((127 << 24) | 1)) { 465 /* 466 * The OS networking stack is expected to drop this kind of 467 * frames since the socket is bound to only localhost address. 468 * Just in case, drop the frame if it is coming from any other 469 * address. 470 */ 471 wpa_printf(MSG_DEBUG, "CTRL: Drop packet from unexpected " 472 "source %s", inet_ntoa(from.sin_addr)); 473 return; 474 } 475 #endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */ 476 477 buf[res] = '\0'; 478 479 if (os_strcmp(buf, "GET_COOKIE") == 0) { 480 reply = wpa_supplicant_global_get_cookie(priv, &reply_len); 481 goto done; 482 } 483 484 if (os_strncmp(buf, "COOKIE=", 7) != 0) { 485 wpa_printf(MSG_DEBUG, "CTLR: No cookie in the request - " 486 "drop request"); 487 return; 488 } 489 490 if (hexstr2bin(buf + 7, cookie, COOKIE_LEN) < 0) { 491 wpa_printf(MSG_DEBUG, "CTLR: Invalid cookie format in the " 492 "request - drop request"); 493 return; 494 } 495 496 if (os_memcmp(cookie, priv->cookie, COOKIE_LEN) != 0) { 497 wpa_printf(MSG_DEBUG, "CTLR: Invalid cookie in the request - " 498 "drop request"); 499 return; 500 } 501 502 pos = buf + 7 + 2 * COOKIE_LEN; 503 while (*pos == ' ') 504 pos++; 505 506 reply = wpa_supplicant_global_ctrl_iface_process(global, pos, 507 &reply_len); 508 509 done: 510 if (reply) { 511 sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, 512 fromlen); 513 os_free(reply); 514 } else if (reply_len) { 515 sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from, 516 fromlen); 517 } 518 } 519 520 521 struct ctrl_iface_global_priv * 522 wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global) 523 { 524 struct ctrl_iface_global_priv *priv; 525 struct sockaddr_in addr; 526 int port = WPA_GLOBAL_CTRL_IFACE_PORT; 527 528 priv = os_zalloc(sizeof(*priv)); 529 if (priv == NULL) 530 return NULL; 531 priv->sock = -1; 532 os_get_random(priv->cookie, COOKIE_LEN); 533 534 if (global->params.ctrl_interface == NULL) 535 return priv; 536 537 wpa_printf(MSG_DEBUG, "Global control interface '%s'", 538 global->params.ctrl_interface); 539 540 priv->sock = socket(PF_INET, SOCK_DGRAM, 0); 541 if (priv->sock < 0) { 542 perror("socket(PF_INET)"); 543 goto fail; 544 } 545 546 os_memset(&addr, 0, sizeof(addr)); 547 addr.sin_family = AF_INET; 548 #ifdef CONFIG_CTRL_IFACE_UDP_REMOTE 549 addr.sin_addr.s_addr = INADDR_ANY; 550 #else /* CONFIG_CTRL_IFACE_UDP_REMOTE */ 551 addr.sin_addr.s_addr = htonl((127 << 24) | 1); 552 #endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */ 553 try_again: 554 addr.sin_port = htons(port); 555 if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { 556 port++; 557 if ((port - WPA_GLOBAL_CTRL_IFACE_PORT) < 558 WPA_GLOBAL_CTRL_IFACE_PORT_LIMIT) 559 goto try_again; 560 perror("bind(AF_INET)"); 561 goto fail; 562 } 563 564 #ifdef CONFIG_CTRL_IFACE_UDP_REMOTE 565 wpa_printf(MSG_DEBUG, "global_ctrl_iface_init UDP port: %d", port); 566 #endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */ 567 568 eloop_register_read_sock(priv->sock, 569 wpa_supplicant_global_ctrl_iface_receive, 570 global, priv); 571 572 return priv; 573 574 fail: 575 if (priv->sock >= 0) 576 close(priv->sock); 577 os_free(priv); 578 return NULL; 579 } 580 581 582 void 583 wpa_supplicant_global_ctrl_iface_deinit(struct ctrl_iface_global_priv *priv) 584 { 585 if (priv->sock >= 0) { 586 eloop_unregister_read_sock(priv->sock); 587 close(priv->sock); 588 } 589 os_free(priv); 590 } 591