761-shared_das_port.patch 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. From: Felix Fietkau <[email protected]>
  2. Date: Fri, 16 Dec 2022 13:32:48 +0100
  3. Subject: [PATCH] hostapd: allow sharing the incoming DAS port across multiple
  4. interfaces
  5. Use the NAS identifier to find the right receiver context on incoming messages
  6. --- a/src/ap/hostapd.c
  7. +++ b/src/ap/hostapd.c
  8. @@ -1387,6 +1387,7 @@ static int hostapd_bss_radius_init(struc
  9. os_memset(&das_conf, 0, sizeof(das_conf));
  10. das_conf.port = conf->radius_das_port;
  11. + das_conf.nas_identifier = conf->nas_identifier;
  12. das_conf.shared_secret = conf->radius_das_shared_secret;
  13. das_conf.shared_secret_len =
  14. conf->radius_das_shared_secret_len;
  15. --- a/src/radius/radius_das.c
  16. +++ b/src/radius/radius_das.c
  17. @@ -12,13 +12,26 @@
  18. #include "utils/common.h"
  19. #include "utils/eloop.h"
  20. #include "utils/ip_addr.h"
  21. +#include "utils/list.h"
  22. #include "radius.h"
  23. #include "radius_das.h"
  24. -struct radius_das_data {
  25. +static struct dl_list das_ports = DL_LIST_HEAD_INIT(das_ports);
  26. +
  27. +struct radius_das_port {
  28. + struct dl_list list;
  29. + struct dl_list das_data;
  30. +
  31. + int port;
  32. int sock;
  33. +};
  34. +
  35. +struct radius_das_data {
  36. + struct dl_list list;
  37. + struct radius_das_port *port;
  38. u8 *shared_secret;
  39. + u8 *nas_identifier;
  40. size_t shared_secret_len;
  41. struct hostapd_ip_addr client_addr;
  42. unsigned int time_window;
  43. @@ -388,56 +401,17 @@ fail:
  44. }
  45. -static void radius_das_receive(int sock, void *eloop_ctx, void *sock_ctx)
  46. +static void
  47. +radius_das_receive_msg(struct radius_das_data *das, struct radius_msg *msg,
  48. + struct sockaddr *from, socklen_t fromlen,
  49. + char *abuf, int from_port)
  50. {
  51. - struct radius_das_data *das = eloop_ctx;
  52. - u8 buf[1500];
  53. - union {
  54. - struct sockaddr_storage ss;
  55. - struct sockaddr_in sin;
  56. -#ifdef CONFIG_IPV6
  57. - struct sockaddr_in6 sin6;
  58. -#endif /* CONFIG_IPV6 */
  59. - } from;
  60. - char abuf[50];
  61. - int from_port = 0;
  62. - socklen_t fromlen;
  63. - int len;
  64. - struct radius_msg *msg, *reply = NULL;
  65. + struct radius_msg *reply = NULL;
  66. struct radius_hdr *hdr;
  67. struct wpabuf *rbuf;
  68. + struct os_time now;
  69. u32 val;
  70. int res;
  71. - struct os_time now;
  72. -
  73. - fromlen = sizeof(from);
  74. - len = recvfrom(sock, buf, sizeof(buf), 0,
  75. - (struct sockaddr *) &from.ss, &fromlen);
  76. - if (len < 0) {
  77. - wpa_printf(MSG_ERROR, "DAS: recvfrom: %s", strerror(errno));
  78. - return;
  79. - }
  80. -
  81. - os_strlcpy(abuf, inet_ntoa(from.sin.sin_addr), sizeof(abuf));
  82. - from_port = ntohs(from.sin.sin_port);
  83. -
  84. - wpa_printf(MSG_DEBUG, "DAS: Received %d bytes from %s:%d",
  85. - len, abuf, from_port);
  86. - if (das->client_addr.u.v4.s_addr &&
  87. - das->client_addr.u.v4.s_addr != from.sin.sin_addr.s_addr) {
  88. - wpa_printf(MSG_DEBUG, "DAS: Drop message from unknown client");
  89. - return;
  90. - }
  91. -
  92. - msg = radius_msg_parse(buf, len);
  93. - if (msg == NULL) {
  94. - wpa_printf(MSG_DEBUG, "DAS: Parsing incoming RADIUS packet "
  95. - "from %s:%d failed", abuf, from_port);
  96. - return;
  97. - }
  98. -
  99. - if (wpa_debug_level <= MSG_MSGDUMP)
  100. - radius_msg_dump(msg);
  101. if (radius_msg_verify_das_req(msg, das->shared_secret,
  102. das->shared_secret_len,
  103. @@ -504,9 +478,8 @@ static void radius_das_receive(int sock,
  104. radius_msg_dump(reply);
  105. rbuf = radius_msg_get_buf(reply);
  106. - res = sendto(das->sock, wpabuf_head(rbuf),
  107. - wpabuf_len(rbuf), 0,
  108. - (struct sockaddr *) &from.ss, fromlen);
  109. + res = sendto(das->port->sock, wpabuf_head(rbuf),
  110. + wpabuf_len(rbuf), 0, from, fromlen);
  111. if (res < 0) {
  112. wpa_printf(MSG_ERROR, "DAS: sendto(to %s:%d): %s",
  113. abuf, from_port, strerror(errno));
  114. @@ -518,6 +491,72 @@ fail:
  115. radius_msg_free(reply);
  116. }
  117. +static void radius_das_receive(int sock, void *eloop_ctx, void *sock_ctx)
  118. +{
  119. + struct radius_das_port *p = eloop_ctx;
  120. + struct radius_das_data *das;
  121. + u8 buf[1500];
  122. + union {
  123. + struct sockaddr_storage ss;
  124. + struct sockaddr_in sin;
  125. +#ifdef CONFIG_IPV6
  126. + struct sockaddr_in6 sin6;
  127. +#endif /* CONFIG_IPV6 */
  128. + } from;
  129. + struct radius_msg *msg;
  130. + size_t nasid_len = 0;
  131. + u8 *nasid_buf = NULL;
  132. + char abuf[50];
  133. + int from_port = 0;
  134. + socklen_t fromlen;
  135. + int found = 0;
  136. + int len;
  137. +
  138. + fromlen = sizeof(from);
  139. + len = recvfrom(sock, buf, sizeof(buf), 0,
  140. + (struct sockaddr *) &from.ss, &fromlen);
  141. + if (len < 0) {
  142. + wpa_printf(MSG_ERROR, "DAS: recvfrom: %s", strerror(errno));
  143. + return;
  144. + }
  145. +
  146. + os_strlcpy(abuf, inet_ntoa(from.sin.sin_addr), sizeof(abuf));
  147. + from_port = ntohs(from.sin.sin_port);
  148. +
  149. + msg = radius_msg_parse(buf, len);
  150. + if (msg == NULL) {
  151. + wpa_printf(MSG_DEBUG, "DAS: Parsing incoming RADIUS packet "
  152. + "from %s:%d failed", abuf, from_port);
  153. + return;
  154. + }
  155. +
  156. + wpa_printf(MSG_DEBUG, "DAS: Received %d bytes from %s:%d",
  157. + len, abuf, from_port);
  158. +
  159. + if (wpa_debug_level <= MSG_MSGDUMP)
  160. + radius_msg_dump(msg);
  161. +
  162. + radius_msg_get_attr_ptr(msg, RADIUS_ATTR_NAS_IDENTIFIER,
  163. + &nasid_buf, &nasid_len, NULL);
  164. + dl_list_for_each(das, &p->das_data, struct radius_das_data, list) {
  165. + if (das->client_addr.u.v4.s_addr &&
  166. + das->client_addr.u.v4.s_addr != from.sin.sin_addr.s_addr)
  167. + continue;
  168. +
  169. + if (das->nas_identifier && nasid_buf &&
  170. + (nasid_len != os_strlen(das->nas_identifier) ||
  171. + os_memcmp(das->nas_identifier, nasid_buf, nasid_len) != 0))
  172. + continue;
  173. +
  174. + found = 1;
  175. + radius_das_receive_msg(das, msg, (struct sockaddr *)&from.ss,
  176. + fromlen, abuf, from_port);
  177. + }
  178. +
  179. + if (!found)
  180. + wpa_printf(MSG_DEBUG, "DAS: Drop message from unknown client");
  181. +}
  182. +
  183. static int radius_das_open_socket(int port)
  184. {
  185. @@ -543,6 +582,49 @@ static int radius_das_open_socket(int po
  186. }
  187. +static struct radius_das_port *
  188. +radius_das_open_port(int port)
  189. +{
  190. + struct radius_das_port *p;
  191. +
  192. + dl_list_for_each(p, &das_ports, struct radius_das_port, list) {
  193. + if (p->port == port)
  194. + return p;
  195. + }
  196. +
  197. + p = os_zalloc(sizeof(*p));
  198. + if (p == NULL)
  199. + return NULL;
  200. +
  201. + dl_list_init(&p->das_data);
  202. + p->port = port;
  203. + p->sock = radius_das_open_socket(port);
  204. + if (p->sock < 0)
  205. + goto free_port;
  206. +
  207. + if (eloop_register_read_sock(p->sock, radius_das_receive, p, NULL))
  208. + goto close_port;
  209. +
  210. + dl_list_add(&das_ports, &p->list);
  211. +
  212. + return p;
  213. +
  214. +close_port:
  215. + close(p->sock);
  216. +free_port:
  217. + os_free(p);
  218. +
  219. + return NULL;
  220. +}
  221. +
  222. +static void radius_das_close_port(struct radius_das_port *p)
  223. +{
  224. + dl_list_del(&p->list);
  225. + eloop_unregister_read_sock(p->sock);
  226. + close(p->sock);
  227. + free(p);
  228. +}
  229. +
  230. struct radius_das_data *
  231. radius_das_init(struct radius_das_conf *conf)
  232. {
  233. @@ -563,6 +645,8 @@ radius_das_init(struct radius_das_conf *
  234. das->ctx = conf->ctx;
  235. das->disconnect = conf->disconnect;
  236. das->coa = conf->coa;
  237. + if (conf->nas_identifier)
  238. + das->nas_identifier = os_strdup(conf->nas_identifier);
  239. os_memcpy(&das->client_addr, conf->client_addr,
  240. sizeof(das->client_addr));
  241. @@ -575,19 +659,15 @@ radius_das_init(struct radius_das_conf *
  242. }
  243. das->shared_secret_len = conf->shared_secret_len;
  244. - das->sock = radius_das_open_socket(conf->port);
  245. - if (das->sock < 0) {
  246. + das->port = radius_das_open_port(conf->port);
  247. + if (!das->port) {
  248. wpa_printf(MSG_ERROR, "Failed to open UDP socket for RADIUS "
  249. "DAS");
  250. radius_das_deinit(das);
  251. return NULL;
  252. }
  253. - if (eloop_register_read_sock(das->sock, radius_das_receive, das, NULL))
  254. - {
  255. - radius_das_deinit(das);
  256. - return NULL;
  257. - }
  258. + dl_list_add(&das->port->das_data, &das->list);
  259. return das;
  260. }
  261. @@ -598,11 +678,14 @@ void radius_das_deinit(struct radius_das
  262. if (das == NULL)
  263. return;
  264. - if (das->sock >= 0) {
  265. - eloop_unregister_read_sock(das->sock);
  266. - close(das->sock);
  267. + if (das->port) {
  268. + dl_list_del(&das->list);
  269. +
  270. + if (dl_list_empty(&das->port->das_data))
  271. + radius_das_close_port(das->port);
  272. }
  273. + os_free(das->nas_identifier);
  274. os_free(das->shared_secret);
  275. os_free(das);
  276. }
  277. --- a/src/radius/radius_das.h
  278. +++ b/src/radius/radius_das.h
  279. @@ -44,6 +44,7 @@ struct radius_das_attrs {
  280. struct radius_das_conf {
  281. int port;
  282. const u8 *shared_secret;
  283. + const u8 *nas_identifier;
  284. size_t shared_secret_len;
  285. const struct hostapd_ip_addr *client_addr;
  286. unsigned int time_window;