wired.c 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. /*
  2. * Received frame processing for wired interface
  3. * Copyright (c) 2010, 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 "utils/includes.h"
  15. #include <net/ethernet.h>
  16. #include <netinet/ip.h>
  17. #include <netinet/udp.h>
  18. #include "utils/common.h"
  19. #include "radius/radius.h"
  20. #include "wlantest.h"
  21. static struct wlantest_radius * radius_get(struct wlantest *wt, u32 srv,
  22. u32 cli)
  23. {
  24. struct wlantest_radius *r;
  25. dl_list_for_each(r, &wt->radius, struct wlantest_radius, list) {
  26. if (r->srv == srv && r->cli == cli)
  27. return r;
  28. }
  29. r = os_zalloc(sizeof(*r));
  30. if (r == NULL)
  31. return NULL;
  32. r->srv = srv;
  33. r->cli = cli;
  34. dl_list_add(&wt->radius, &r->list);
  35. return r;
  36. }
  37. static const char * radius_code_string(u8 code)
  38. {
  39. switch (code) {
  40. case RADIUS_CODE_ACCESS_REQUEST:
  41. return "Access-Request";
  42. case RADIUS_CODE_ACCESS_ACCEPT:
  43. return "Access-Accept";
  44. case RADIUS_CODE_ACCESS_REJECT:
  45. return "Access-Reject";
  46. case RADIUS_CODE_ACCOUNTING_REQUEST:
  47. return "Accounting-Request";
  48. case RADIUS_CODE_ACCOUNTING_RESPONSE:
  49. return "Accounting-Response";
  50. case RADIUS_CODE_ACCESS_CHALLENGE:
  51. return "Access-Challenge";
  52. case RADIUS_CODE_STATUS_SERVER:
  53. return "Status-Server";
  54. case RADIUS_CODE_STATUS_CLIENT:
  55. return "Status-Client";
  56. case RADIUS_CODE_RESERVED:
  57. return "Reserved";
  58. default:
  59. return "?Unknown?";
  60. }
  61. }
  62. static void process_radius_access_request(struct wlantest *wt, u32 dst,
  63. u32 src, const u8 *data, size_t len)
  64. {
  65. struct radius_msg *msg;
  66. struct wlantest_radius *r;
  67. msg = radius_msg_parse(data, len);
  68. if (msg == NULL) {
  69. wpa_printf(MSG_DEBUG, "Failed to parse RADIUS Access-Request");
  70. return;
  71. }
  72. r = radius_get(wt, dst, src);
  73. if (r) {
  74. radius_msg_free(r->last_req);
  75. r->last_req = msg;
  76. return;
  77. }
  78. radius_msg_free(msg);
  79. }
  80. static void wlantest_add_pmk(struct wlantest *wt, const u8 *pmk)
  81. {
  82. struct wlantest_pmk *p;
  83. p = os_zalloc(sizeof(*p));
  84. if (p == NULL)
  85. return;
  86. os_memcpy(p->pmk, pmk, 32);
  87. dl_list_add(&wt->pmk, &p->list);
  88. wpa_hexdump(MSG_INFO, "Add PMK", pmk, 32);
  89. }
  90. static void process_radius_access_accept(struct wlantest *wt, u32 dst, u32 src,
  91. const u8 *data, size_t len)
  92. {
  93. struct radius_msg *msg;
  94. struct wlantest_radius *r;
  95. struct radius_ms_mppe_keys *keys;
  96. struct wlantest_radius_secret *s;
  97. r = radius_get(wt, src, dst);
  98. if (r == NULL || r->last_req == NULL) {
  99. wpa_printf(MSG_DEBUG, "No RADIUS Access-Challenge found for "
  100. "decrypting Access-Accept keys");
  101. return;
  102. }
  103. msg = radius_msg_parse(data, len);
  104. if (msg == NULL) {
  105. wpa_printf(MSG_DEBUG, "Failed to parse RADIUS Access-Accept");
  106. return;
  107. }
  108. dl_list_for_each(s, &wt->secret, struct wlantest_radius_secret, list) {
  109. int found = 0;
  110. keys = radius_msg_get_ms_keys(msg, r->last_req,
  111. (u8 *) s->secret,
  112. os_strlen(s->secret));
  113. if (keys && keys->send && keys->recv) {
  114. u8 pmk[32];
  115. wpa_hexdump_key(MSG_DEBUG, "MS-MPPE-Send-Key",
  116. keys->send, keys->send_len);
  117. wpa_hexdump_key(MSG_DEBUG, "MS-MPPE-Recv-Key",
  118. keys->recv, keys->recv_len);
  119. os_memcpy(pmk, keys->recv,
  120. keys->recv_len > 32 ? 32 : keys->recv_len);
  121. if (keys->recv_len < 32) {
  122. os_memcpy(pmk + keys->recv_len,
  123. keys->send,
  124. keys->recv_len + keys->send_len > 32
  125. ? 32 : 32 - keys->recv_len);
  126. }
  127. wlantest_add_pmk(wt, pmk);
  128. found = 1;
  129. }
  130. if (keys) {
  131. os_free(keys->send);
  132. os_free(keys->recv);
  133. os_free(keys);
  134. }
  135. if (found)
  136. break;
  137. }
  138. radius_msg_free(msg);
  139. }
  140. static void process_radius(struct wlantest *wt, u32 dst, u16 dport, u32 src,
  141. u16 sport, const u8 *data, size_t len)
  142. {
  143. struct in_addr addr;
  144. char buf[20];
  145. const struct radius_hdr *hdr;
  146. u16 rlen;
  147. if (len < sizeof(*hdr))
  148. return;
  149. hdr = (const struct radius_hdr *) data;
  150. rlen = be_to_host16(hdr->length);
  151. if (len < rlen)
  152. return;
  153. if (len > rlen)
  154. len = rlen;
  155. addr.s_addr = dst;
  156. snprintf(buf, sizeof(buf), "%s", inet_ntoa(addr));
  157. addr.s_addr = src;
  158. wpa_printf(MSG_DEBUG, "RADIUS %s:%u -> %s:%u id=%u %s",
  159. inet_ntoa(addr), sport, buf, dport, hdr->identifier,
  160. radius_code_string(hdr->code));
  161. switch (hdr->code) {
  162. case RADIUS_CODE_ACCESS_REQUEST:
  163. process_radius_access_request(wt, dst, src, data, len);
  164. break;
  165. case RADIUS_CODE_ACCESS_ACCEPT:
  166. process_radius_access_accept(wt, dst, src, data, len);
  167. break;
  168. }
  169. }
  170. static void process_udp(struct wlantest *wt, u32 dst, u32 src,
  171. const u8 *data, size_t len)
  172. {
  173. const struct udphdr *udp;
  174. u16 sport, dport, ulen;
  175. const u8 *payload;
  176. size_t plen;
  177. if (len < sizeof(*udp))
  178. return;
  179. udp = (const struct udphdr *) data;
  180. /* TODO: check UDP checksum */
  181. sport = be_to_host16(udp->source);
  182. dport = be_to_host16(udp->dest);
  183. ulen = be_to_host16(udp->len);
  184. if (ulen > len)
  185. return;
  186. if (len < ulen)
  187. len = ulen;
  188. payload = (const u8 *) (udp + 1);
  189. plen = len - sizeof(*udp);
  190. if (sport == 1812 || dport == 1812)
  191. process_radius(wt, dst, dport, src, sport, payload, plen);
  192. }
  193. static void process_ipv4(struct wlantest *wt, const u8 *data, size_t len)
  194. {
  195. const struct iphdr *ip;
  196. const u8 *payload;
  197. size_t plen;
  198. u16 frag_off, tot_len;
  199. if (len < sizeof(*ip))
  200. return;
  201. ip = (const struct iphdr *) data;
  202. if (ip->version != 4)
  203. return;
  204. if (ip->ihl < 5)
  205. return;
  206. /* TODO: check header checksum in ip->check */
  207. frag_off = be_to_host16(ip->frag_off);
  208. if (frag_off & 0x1fff) {
  209. wpa_printf(MSG_EXCESSIVE, "IP fragment reassembly not yet "
  210. "supported");
  211. return;
  212. }
  213. tot_len = be_to_host16(ip->tot_len);
  214. if (tot_len > len)
  215. return;
  216. if (tot_len < len)
  217. len = tot_len;
  218. payload = data + 4 * ip->ihl;
  219. plen = len - 4 * ip->ihl;
  220. if (payload + plen > data + len)
  221. return;
  222. switch (ip->protocol) {
  223. case IPPROTO_UDP:
  224. process_udp(wt, ip->daddr, ip->saddr, payload, plen);
  225. break;
  226. }
  227. }
  228. void wlantest_process_wired(struct wlantest *wt, const u8 *data, size_t len)
  229. {
  230. const struct ether_header *eth;
  231. u16 ethertype;
  232. wpa_hexdump(MSG_EXCESSIVE, "Process wired frame", data, len);
  233. if (len < sizeof(*eth))
  234. return;
  235. eth = (const struct ether_header *) data;
  236. ethertype = be_to_host16(eth->ether_type);
  237. switch (ethertype) {
  238. case ETHERTYPE_IP:
  239. process_ipv4(wt, data + sizeof(*eth), len - sizeof(*eth));
  240. break;
  241. }
  242. }