| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305 |
- From: Felix Fietkau <[email protected]>
- Date: Fri, 16 Dec 2022 13:32:48 +0100
- Subject: [PATCH] hostapd: allow sharing the incoming DAS port across multiple
- interfaces
- Use the NAS identifier to find the right receiver context on incoming messages
- --- a/src/ap/hostapd.c
- +++ b/src/ap/hostapd.c
- @@ -1387,6 +1387,7 @@ static int hostapd_bss_radius_init(struc
-
- os_memset(&das_conf, 0, sizeof(das_conf));
- das_conf.port = conf->radius_das_port;
- + das_conf.nas_identifier = conf->nas_identifier;
- das_conf.shared_secret = conf->radius_das_shared_secret;
- das_conf.shared_secret_len =
- conf->radius_das_shared_secret_len;
- --- a/src/radius/radius_das.c
- +++ b/src/radius/radius_das.c
- @@ -12,13 +12,26 @@
- #include "utils/common.h"
- #include "utils/eloop.h"
- #include "utils/ip_addr.h"
- +#include "utils/list.h"
- #include "radius.h"
- #include "radius_das.h"
-
-
- -struct radius_das_data {
- +static struct dl_list das_ports = DL_LIST_HEAD_INIT(das_ports);
- +
- +struct radius_das_port {
- + struct dl_list list;
- + struct dl_list das_data;
- +
- + int port;
- int sock;
- +};
- +
- +struct radius_das_data {
- + struct dl_list list;
- + struct radius_das_port *port;
- u8 *shared_secret;
- + u8 *nas_identifier;
- size_t shared_secret_len;
- struct hostapd_ip_addr client_addr;
- unsigned int time_window;
- @@ -388,56 +401,17 @@ fail:
- }
-
-
- -static void radius_das_receive(int sock, void *eloop_ctx, void *sock_ctx)
- +static void
- +radius_das_receive_msg(struct radius_das_data *das, struct radius_msg *msg,
- + struct sockaddr *from, socklen_t fromlen,
- + char *abuf, int from_port)
- {
- - struct radius_das_data *das = eloop_ctx;
- - u8 buf[1500];
- - union {
- - struct sockaddr_storage ss;
- - struct sockaddr_in sin;
- -#ifdef CONFIG_IPV6
- - struct sockaddr_in6 sin6;
- -#endif /* CONFIG_IPV6 */
- - } from;
- - char abuf[50];
- - int from_port = 0;
- - socklen_t fromlen;
- - int len;
- - struct radius_msg *msg, *reply = NULL;
- + struct radius_msg *reply = NULL;
- struct radius_hdr *hdr;
- struct wpabuf *rbuf;
- + struct os_time now;
- u32 val;
- int res;
- - struct os_time now;
- -
- - fromlen = sizeof(from);
- - len = recvfrom(sock, buf, sizeof(buf), 0,
- - (struct sockaddr *) &from.ss, &fromlen);
- - if (len < 0) {
- - wpa_printf(MSG_ERROR, "DAS: recvfrom: %s", strerror(errno));
- - return;
- - }
- -
- - os_strlcpy(abuf, inet_ntoa(from.sin.sin_addr), sizeof(abuf));
- - from_port = ntohs(from.sin.sin_port);
- -
- - wpa_printf(MSG_DEBUG, "DAS: Received %d bytes from %s:%d",
- - len, abuf, from_port);
- - if (das->client_addr.u.v4.s_addr &&
- - das->client_addr.u.v4.s_addr != from.sin.sin_addr.s_addr) {
- - wpa_printf(MSG_DEBUG, "DAS: Drop message from unknown client");
- - return;
- - }
- -
- - msg = radius_msg_parse(buf, len);
- - if (msg == NULL) {
- - wpa_printf(MSG_DEBUG, "DAS: Parsing incoming RADIUS packet "
- - "from %s:%d failed", abuf, from_port);
- - return;
- - }
- -
- - if (wpa_debug_level <= MSG_MSGDUMP)
- - radius_msg_dump(msg);
-
- if (radius_msg_verify_das_req(msg, das->shared_secret,
- das->shared_secret_len,
- @@ -504,9 +478,8 @@ static void radius_das_receive(int sock,
- radius_msg_dump(reply);
-
- rbuf = radius_msg_get_buf(reply);
- - res = sendto(das->sock, wpabuf_head(rbuf),
- - wpabuf_len(rbuf), 0,
- - (struct sockaddr *) &from.ss, fromlen);
- + res = sendto(das->port->sock, wpabuf_head(rbuf),
- + wpabuf_len(rbuf), 0, from, fromlen);
- if (res < 0) {
- wpa_printf(MSG_ERROR, "DAS: sendto(to %s:%d): %s",
- abuf, from_port, strerror(errno));
- @@ -518,6 +491,72 @@ fail:
- radius_msg_free(reply);
- }
-
- +static void radius_das_receive(int sock, void *eloop_ctx, void *sock_ctx)
- +{
- + struct radius_das_port *p = eloop_ctx;
- + struct radius_das_data *das;
- + u8 buf[1500];
- + union {
- + struct sockaddr_storage ss;
- + struct sockaddr_in sin;
- +#ifdef CONFIG_IPV6
- + struct sockaddr_in6 sin6;
- +#endif /* CONFIG_IPV6 */
- + } from;
- + struct radius_msg *msg;
- + size_t nasid_len = 0;
- + u8 *nasid_buf = NULL;
- + char abuf[50];
- + int from_port = 0;
- + socklen_t fromlen;
- + int found = 0;
- + int len;
- +
- + fromlen = sizeof(from);
- + len = recvfrom(sock, buf, sizeof(buf), 0,
- + (struct sockaddr *) &from.ss, &fromlen);
- + if (len < 0) {
- + wpa_printf(MSG_ERROR, "DAS: recvfrom: %s", strerror(errno));
- + return;
- + }
- +
- + os_strlcpy(abuf, inet_ntoa(from.sin.sin_addr), sizeof(abuf));
- + from_port = ntohs(from.sin.sin_port);
- +
- + msg = radius_msg_parse(buf, len);
- + if (msg == NULL) {
- + wpa_printf(MSG_DEBUG, "DAS: Parsing incoming RADIUS packet "
- + "from %s:%d failed", abuf, from_port);
- + return;
- + }
- +
- + wpa_printf(MSG_DEBUG, "DAS: Received %d bytes from %s:%d",
- + len, abuf, from_port);
- +
- + if (wpa_debug_level <= MSG_MSGDUMP)
- + radius_msg_dump(msg);
- +
- + radius_msg_get_attr_ptr(msg, RADIUS_ATTR_NAS_IDENTIFIER,
- + &nasid_buf, &nasid_len, NULL);
- + dl_list_for_each(das, &p->das_data, struct radius_das_data, list) {
- + if (das->client_addr.u.v4.s_addr &&
- + das->client_addr.u.v4.s_addr != from.sin.sin_addr.s_addr)
- + continue;
- +
- + if (das->nas_identifier && nasid_buf &&
- + (nasid_len != os_strlen(das->nas_identifier) ||
- + os_memcmp(das->nas_identifier, nasid_buf, nasid_len) != 0))
- + continue;
- +
- + found = 1;
- + radius_das_receive_msg(das, msg, (struct sockaddr *)&from.ss,
- + fromlen, abuf, from_port);
- + }
- +
- + if (!found)
- + wpa_printf(MSG_DEBUG, "DAS: Drop message from unknown client");
- +}
- +
-
- static int radius_das_open_socket(int port)
- {
- @@ -543,6 +582,49 @@ static int radius_das_open_socket(int po
- }
-
-
- +static struct radius_das_port *
- +radius_das_open_port(int port)
- +{
- + struct radius_das_port *p;
- +
- + dl_list_for_each(p, &das_ports, struct radius_das_port, list) {
- + if (p->port == port)
- + return p;
- + }
- +
- + p = os_zalloc(sizeof(*p));
- + if (p == NULL)
- + return NULL;
- +
- + dl_list_init(&p->das_data);
- + p->port = port;
- + p->sock = radius_das_open_socket(port);
- + if (p->sock < 0)
- + goto free_port;
- +
- + if (eloop_register_read_sock(p->sock, radius_das_receive, p, NULL))
- + goto close_port;
- +
- + dl_list_add(&das_ports, &p->list);
- +
- + return p;
- +
- +close_port:
- + close(p->sock);
- +free_port:
- + os_free(p);
- +
- + return NULL;
- +}
- +
- +static void radius_das_close_port(struct radius_das_port *p)
- +{
- + dl_list_del(&p->list);
- + eloop_unregister_read_sock(p->sock);
- + close(p->sock);
- + free(p);
- +}
- +
- struct radius_das_data *
- radius_das_init(struct radius_das_conf *conf)
- {
- @@ -563,6 +645,8 @@ radius_das_init(struct radius_das_conf *
- das->ctx = conf->ctx;
- das->disconnect = conf->disconnect;
- das->coa = conf->coa;
- + if (conf->nas_identifier)
- + das->nas_identifier = os_strdup(conf->nas_identifier);
-
- os_memcpy(&das->client_addr, conf->client_addr,
- sizeof(das->client_addr));
- @@ -575,19 +659,15 @@ radius_das_init(struct radius_das_conf *
- }
- das->shared_secret_len = conf->shared_secret_len;
-
- - das->sock = radius_das_open_socket(conf->port);
- - if (das->sock < 0) {
- + das->port = radius_das_open_port(conf->port);
- + if (!das->port) {
- wpa_printf(MSG_ERROR, "Failed to open UDP socket for RADIUS "
- "DAS");
- radius_das_deinit(das);
- return NULL;
- }
-
- - if (eloop_register_read_sock(das->sock, radius_das_receive, das, NULL))
- - {
- - radius_das_deinit(das);
- - return NULL;
- - }
- + dl_list_add(&das->port->das_data, &das->list);
-
- return das;
- }
- @@ -598,11 +678,14 @@ void radius_das_deinit(struct radius_das
- if (das == NULL)
- return;
-
- - if (das->sock >= 0) {
- - eloop_unregister_read_sock(das->sock);
- - close(das->sock);
- + if (das->port) {
- + dl_list_del(&das->list);
- +
- + if (dl_list_empty(&das->port->das_data))
- + radius_das_close_port(das->port);
- }
-
- + os_free(das->nas_identifier);
- os_free(das->shared_secret);
- os_free(das);
- }
- --- a/src/radius/radius_das.h
- +++ b/src/radius/radius_das.h
- @@ -44,6 +44,7 @@ struct radius_das_attrs {
- struct radius_das_conf {
- int port;
- const u8 *shared_secret;
- + const u8 *nas_identifier;
- size_t shared_secret_len;
- const struct hostapd_ip_addr *client_addr;
- unsigned int time_window;
|