Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

ctrl_iface_udp.c 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561
  1. /*
  2. * WPA Supplicant / UDP socket -based control interface
  3. * Copyright (c) 2004-2005, Jouni Malinen <j@w1.fi>
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License version 2 as
  7. * published by the Free Software Foundation.
  8. *
  9. * Alternatively, this software may be distributed under the terms of BSD
  10. * license.
  11. *
  12. * See README and COPYING for more details.
  13. */
  14. #include "includes.h"
  15. #include "common.h"
  16. #include "eloop.h"
  17. #include "config.h"
  18. #include "eapol_supp/eapol_supp_sm.h"
  19. #include "wpa_supplicant_i.h"
  20. #include "ctrl_iface.h"
  21. #include "common/wpa_ctrl.h"
  22. #define COOKIE_LEN 8
  23. /* Per-interface ctrl_iface */
  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. struct ctrl_iface_priv {
  39. struct wpa_supplicant *wpa_s;
  40. int sock;
  41. struct wpa_ctrl_dst *ctrl_dst;
  42. u8 cookie[COOKIE_LEN];
  43. };
  44. static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv,
  45. int level, const char *buf,
  46. size_t len);
  47. static int wpa_supplicant_ctrl_iface_attach(struct ctrl_iface_priv *priv,
  48. struct sockaddr_in *from,
  49. socklen_t fromlen)
  50. {
  51. struct wpa_ctrl_dst *dst;
  52. dst = os_zalloc(sizeof(*dst));
  53. if (dst == NULL)
  54. return -1;
  55. os_memcpy(&dst->addr, from, sizeof(struct sockaddr_in));
  56. dst->addrlen = fromlen;
  57. dst->debug_level = MSG_INFO;
  58. dst->next = priv->ctrl_dst;
  59. priv->ctrl_dst = dst;
  60. wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor attached %s:%d",
  61. inet_ntoa(from->sin_addr), ntohs(from->sin_port));
  62. return 0;
  63. }
  64. static int wpa_supplicant_ctrl_iface_detach(struct ctrl_iface_priv *priv,
  65. struct sockaddr_in *from,
  66. socklen_t fromlen)
  67. {
  68. struct wpa_ctrl_dst *dst, *prev = NULL;
  69. dst = priv->ctrl_dst;
  70. while (dst) {
  71. if (from->sin_addr.s_addr == dst->addr.sin_addr.s_addr &&
  72. from->sin_port == dst->addr.sin_port) {
  73. if (prev == NULL)
  74. priv->ctrl_dst = dst->next;
  75. else
  76. prev->next = dst->next;
  77. os_free(dst);
  78. wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor detached "
  79. "%s:%d", inet_ntoa(from->sin_addr),
  80. ntohs(from->sin_port));
  81. return 0;
  82. }
  83. prev = dst;
  84. dst = dst->next;
  85. }
  86. return -1;
  87. }
  88. static int wpa_supplicant_ctrl_iface_level(struct ctrl_iface_priv *priv,
  89. struct sockaddr_in *from,
  90. socklen_t fromlen,
  91. char *level)
  92. {
  93. struct wpa_ctrl_dst *dst;
  94. wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", level);
  95. dst = priv->ctrl_dst;
  96. while (dst) {
  97. if (from->sin_addr.s_addr == dst->addr.sin_addr.s_addr &&
  98. from->sin_port == dst->addr.sin_port) {
  99. wpa_printf(MSG_DEBUG, "CTRL_IFACE changed monitor "
  100. "level %s:%d", inet_ntoa(from->sin_addr),
  101. ntohs(from->sin_port));
  102. dst->debug_level = atoi(level);
  103. return 0;
  104. }
  105. dst = dst->next;
  106. }
  107. return -1;
  108. }
  109. static char *
  110. wpa_supplicant_ctrl_iface_get_cookie(struct ctrl_iface_priv *priv,
  111. size_t *reply_len)
  112. {
  113. char *reply;
  114. reply = os_malloc(7 + 2 * COOKIE_LEN + 1);
  115. if (reply == NULL) {
  116. *reply_len = 1;
  117. return NULL;
  118. }
  119. os_memcpy(reply, "COOKIE=", 7);
  120. wpa_snprintf_hex(reply + 7, 2 * COOKIE_LEN + 1,
  121. priv->cookie, COOKIE_LEN);
  122. *reply_len = 7 + 2 * COOKIE_LEN;
  123. return reply;
  124. }
  125. static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx,
  126. void *sock_ctx)
  127. {
  128. struct wpa_supplicant *wpa_s = eloop_ctx;
  129. struct ctrl_iface_priv *priv = sock_ctx;
  130. char buf[256], *pos;
  131. int res;
  132. struct sockaddr_in from;
  133. socklen_t fromlen = sizeof(from);
  134. char *reply = NULL;
  135. size_t reply_len = 0;
  136. int new_attached = 0;
  137. u8 cookie[COOKIE_LEN];
  138. res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
  139. (struct sockaddr *) &from, &fromlen);
  140. if (res < 0) {
  141. perror("recvfrom(ctrl_iface)");
  142. return;
  143. }
  144. if (from.sin_addr.s_addr != htonl((127 << 24) | 1)) {
  145. /*
  146. * The OS networking stack is expected to drop this kind of
  147. * frames since the socket is bound to only localhost address.
  148. * Just in case, drop the frame if it is coming from any other
  149. * address.
  150. */
  151. wpa_printf(MSG_DEBUG, "CTRL: Drop packet from unexpected "
  152. "source %s", inet_ntoa(from.sin_addr));
  153. return;
  154. }
  155. buf[res] = '\0';
  156. if (os_strcmp(buf, "GET_COOKIE") == 0) {
  157. reply = wpa_supplicant_ctrl_iface_get_cookie(priv, &reply_len);
  158. goto done;
  159. }
  160. /*
  161. * Require that the client includes a prefix with the 'cookie' value
  162. * fetched with GET_COOKIE command. This is used to verify that the
  163. * client has access to a bidirectional link over UDP in order to
  164. * avoid attacks using forged localhost IP address even if the OS does
  165. * not block such frames from remote destinations.
  166. */
  167. if (os_strncmp(buf, "COOKIE=", 7) != 0) {
  168. wpa_printf(MSG_DEBUG, "CTLR: No cookie in the request - "
  169. "drop request");
  170. return;
  171. }
  172. if (hexstr2bin(buf + 7, cookie, COOKIE_LEN) < 0) {
  173. wpa_printf(MSG_DEBUG, "CTLR: Invalid cookie format in the "
  174. "request - drop request");
  175. return;
  176. }
  177. if (os_memcmp(cookie, priv->cookie, COOKIE_LEN) != 0) {
  178. wpa_printf(MSG_DEBUG, "CTLR: Invalid cookie in the request - "
  179. "drop request");
  180. return;
  181. }
  182. pos = buf + 7 + 2 * COOKIE_LEN;
  183. while (*pos == ' ')
  184. pos++;
  185. if (os_strcmp(pos, "ATTACH") == 0) {
  186. if (wpa_supplicant_ctrl_iface_attach(priv, &from, fromlen))
  187. reply_len = 1;
  188. else {
  189. new_attached = 1;
  190. reply_len = 2;
  191. }
  192. } else if (os_strcmp(pos, "DETACH") == 0) {
  193. if (wpa_supplicant_ctrl_iface_detach(priv, &from, fromlen))
  194. reply_len = 1;
  195. else
  196. reply_len = 2;
  197. } else if (os_strncmp(pos, "LEVEL ", 6) == 0) {
  198. if (wpa_supplicant_ctrl_iface_level(priv, &from, fromlen,
  199. pos + 6))
  200. reply_len = 1;
  201. else
  202. reply_len = 2;
  203. } else {
  204. reply = wpa_supplicant_ctrl_iface_process(wpa_s, pos,
  205. &reply_len);
  206. }
  207. done:
  208. if (reply) {
  209. sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,
  210. fromlen);
  211. os_free(reply);
  212. } else if (reply_len == 1) {
  213. sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
  214. fromlen);
  215. } else if (reply_len == 2) {
  216. sendto(sock, "OK\n", 3, 0, (struct sockaddr *) &from,
  217. fromlen);
  218. }
  219. if (new_attached)
  220. eapol_sm_notify_ctrl_attached(wpa_s->eapol);
  221. }
  222. static void wpa_supplicant_ctrl_iface_msg_cb(void *ctx, int level,
  223. const char *txt, size_t len)
  224. {
  225. struct wpa_supplicant *wpa_s = ctx;
  226. if (wpa_s == NULL || wpa_s->ctrl_iface == NULL)
  227. return;
  228. wpa_supplicant_ctrl_iface_send(wpa_s->ctrl_iface, level, txt, len);
  229. }
  230. struct ctrl_iface_priv *
  231. wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
  232. {
  233. struct ctrl_iface_priv *priv;
  234. struct sockaddr_in addr;
  235. priv = os_zalloc(sizeof(*priv));
  236. if (priv == NULL)
  237. return NULL;
  238. priv->wpa_s = wpa_s;
  239. priv->sock = -1;
  240. os_get_random(priv->cookie, COOKIE_LEN);
  241. if (wpa_s->conf->ctrl_interface == NULL)
  242. return priv;
  243. priv->sock = socket(PF_INET, SOCK_DGRAM, 0);
  244. if (priv->sock < 0) {
  245. perror("socket(PF_INET)");
  246. goto fail;
  247. }
  248. os_memset(&addr, 0, sizeof(addr));
  249. addr.sin_family = AF_INET;
  250. addr.sin_addr.s_addr = htonl((127 << 24) | 1);
  251. addr.sin_port = htons(WPA_CTRL_IFACE_PORT);
  252. if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
  253. perror("bind(AF_INET)");
  254. goto fail;
  255. }
  256. eloop_register_read_sock(priv->sock, wpa_supplicant_ctrl_iface_receive,
  257. wpa_s, priv);
  258. wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb);
  259. return priv;
  260. fail:
  261. if (priv->sock >= 0)
  262. close(priv->sock);
  263. os_free(priv);
  264. return NULL;
  265. }
  266. void wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv)
  267. {
  268. struct wpa_ctrl_dst *dst, *prev;
  269. if (priv->sock > -1) {
  270. eloop_unregister_read_sock(priv->sock);
  271. if (priv->ctrl_dst) {
  272. /*
  273. * Wait a second before closing the control socket if
  274. * there are any attached monitors in order to allow
  275. * them to receive any pending messages.
  276. */
  277. wpa_printf(MSG_DEBUG, "CTRL_IFACE wait for attached "
  278. "monitors to receive messages");
  279. os_sleep(1, 0);
  280. }
  281. close(priv->sock);
  282. priv->sock = -1;
  283. }
  284. dst = priv->ctrl_dst;
  285. while (dst) {
  286. prev = dst;
  287. dst = dst->next;
  288. os_free(prev);
  289. }
  290. os_free(priv);
  291. }
  292. static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv,
  293. int level, const char *buf,
  294. size_t len)
  295. {
  296. struct wpa_ctrl_dst *dst, *next;
  297. char levelstr[10];
  298. int idx;
  299. char *sbuf;
  300. int llen;
  301. dst = priv->ctrl_dst;
  302. if (priv->sock < 0 || dst == NULL)
  303. return;
  304. os_snprintf(levelstr, sizeof(levelstr), "<%d>", level);
  305. llen = os_strlen(levelstr);
  306. sbuf = os_malloc(llen + len);
  307. if (sbuf == NULL)
  308. return;
  309. os_memcpy(sbuf, levelstr, llen);
  310. os_memcpy(sbuf + llen, buf, len);
  311. idx = 0;
  312. while (dst) {
  313. next = dst->next;
  314. if (level >= dst->debug_level) {
  315. wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor send %s:%d",
  316. inet_ntoa(dst->addr.sin_addr),
  317. ntohs(dst->addr.sin_port));
  318. if (sendto(priv->sock, sbuf, llen + len, 0,
  319. (struct sockaddr *) &dst->addr,
  320. sizeof(dst->addr)) < 0) {
  321. perror("sendto(CTRL_IFACE monitor)");
  322. dst->errors++;
  323. if (dst->errors > 10) {
  324. wpa_supplicant_ctrl_iface_detach(
  325. priv, &dst->addr,
  326. dst->addrlen);
  327. }
  328. } else
  329. dst->errors = 0;
  330. }
  331. idx++;
  332. dst = next;
  333. }
  334. os_free(sbuf);
  335. }
  336. void wpa_supplicant_ctrl_iface_wait(struct ctrl_iface_priv *priv)
  337. {
  338. wpa_printf(MSG_DEBUG, "CTRL_IFACE - %s - wait for monitor",
  339. priv->wpa_s->ifname);
  340. eloop_wait_for_read_sock(priv->sock);
  341. }
  342. /* Global ctrl_iface */
  343. struct ctrl_iface_global_priv {
  344. int sock;
  345. u8 cookie[COOKIE_LEN];
  346. };
  347. static char *
  348. wpa_supplicant_global_get_cookie(struct ctrl_iface_global_priv *priv,
  349. size_t *reply_len)
  350. {
  351. char *reply;
  352. reply = os_malloc(7 + 2 * COOKIE_LEN + 1);
  353. if (reply == NULL) {
  354. *reply_len = 1;
  355. return NULL;
  356. }
  357. os_memcpy(reply, "COOKIE=", 7);
  358. wpa_snprintf_hex(reply + 7, 2 * COOKIE_LEN + 1,
  359. priv->cookie, COOKIE_LEN);
  360. *reply_len = 7 + 2 * COOKIE_LEN;
  361. return reply;
  362. }
  363. static void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx,
  364. void *sock_ctx)
  365. {
  366. struct wpa_global *global = eloop_ctx;
  367. struct ctrl_iface_global_priv *priv = sock_ctx;
  368. char buf[256], *pos;
  369. int res;
  370. struct sockaddr_in from;
  371. socklen_t fromlen = sizeof(from);
  372. char *reply;
  373. size_t reply_len;
  374. u8 cookie[COOKIE_LEN];
  375. res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
  376. (struct sockaddr *) &from, &fromlen);
  377. if (res < 0) {
  378. perror("recvfrom(ctrl_iface)");
  379. return;
  380. }
  381. if (from.sin_addr.s_addr != htonl((127 << 24) | 1)) {
  382. /*
  383. * The OS networking stack is expected to drop this kind of
  384. * frames since the socket is bound to only localhost address.
  385. * Just in case, drop the frame if it is coming from any other
  386. * address.
  387. */
  388. wpa_printf(MSG_DEBUG, "CTRL: Drop packet from unexpected "
  389. "source %s", inet_ntoa(from.sin_addr));
  390. return;
  391. }
  392. buf[res] = '\0';
  393. if (os_strcmp(buf, "GET_COOKIE") == 0) {
  394. reply = wpa_supplicant_global_get_cookie(priv, &reply_len);
  395. goto done;
  396. }
  397. if (os_strncmp(buf, "COOKIE=", 7) != 0) {
  398. wpa_printf(MSG_DEBUG, "CTLR: No cookie in the request - "
  399. "drop request");
  400. return;
  401. }
  402. if (hexstr2bin(buf + 7, cookie, COOKIE_LEN) < 0) {
  403. wpa_printf(MSG_DEBUG, "CTLR: Invalid cookie format in the "
  404. "request - drop request");
  405. return;
  406. }
  407. if (os_memcmp(cookie, priv->cookie, COOKIE_LEN) != 0) {
  408. wpa_printf(MSG_DEBUG, "CTLR: Invalid cookie in the request - "
  409. "drop request");
  410. return;
  411. }
  412. pos = buf + 7 + 2 * COOKIE_LEN;
  413. while (*pos == ' ')
  414. pos++;
  415. reply = wpa_supplicant_global_ctrl_iface_process(global, pos,
  416. &reply_len);
  417. done:
  418. if (reply) {
  419. sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,
  420. fromlen);
  421. os_free(reply);
  422. } else if (reply_len) {
  423. sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
  424. fromlen);
  425. }
  426. }
  427. struct ctrl_iface_global_priv *
  428. wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global)
  429. {
  430. struct ctrl_iface_global_priv *priv;
  431. struct sockaddr_in addr;
  432. priv = os_zalloc(sizeof(*priv));
  433. if (priv == NULL)
  434. return NULL;
  435. priv->sock = -1;
  436. os_get_random(priv->cookie, COOKIE_LEN);
  437. if (global->params.ctrl_interface == NULL)
  438. return priv;
  439. wpa_printf(MSG_DEBUG, "Global control interface '%s'",
  440. global->params.ctrl_interface);
  441. priv->sock = socket(PF_INET, SOCK_DGRAM, 0);
  442. if (priv->sock < 0) {
  443. perror("socket(PF_INET)");
  444. goto fail;
  445. }
  446. os_memset(&addr, 0, sizeof(addr));
  447. addr.sin_family = AF_INET;
  448. addr.sin_addr.s_addr = htonl((127 << 24) | 1);
  449. addr.sin_port = htons(WPA_GLOBAL_CTRL_IFACE_PORT);
  450. if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
  451. perror("bind(AF_INET)");
  452. goto fail;
  453. }
  454. eloop_register_read_sock(priv->sock,
  455. wpa_supplicant_global_ctrl_iface_receive,
  456. global, priv);
  457. return priv;
  458. fail:
  459. if (priv->sock >= 0)
  460. close(priv->sock);
  461. os_free(priv);
  462. return NULL;
  463. }
  464. void
  465. wpa_supplicant_global_ctrl_iface_deinit(struct ctrl_iface_global_priv *priv)
  466. {
  467. if (priv->sock >= 0) {
  468. eloop_unregister_read_sock(priv->sock);
  469. close(priv->sock);
  470. }
  471. os_free(priv);
  472. }