1 From: Felix Fietkau <nbd@nbd.name>
2 Date: Fri, 16 Dec 2022 13:32:48 +0100
3 Subject: [PATCH] hostapd: allow sharing the incoming DAS port across multiple
6 Use the NAS identifier to find the right receiver context on incoming messages
10 @@ -1510,6 +1510,7 @@ int hostapd_setup_bss(struct hostapd_dat
12 os_memset(&das_conf, 0, sizeof(das_conf));
13 das_conf.port = conf->radius_das_port;
14 + das_conf.nas_identifier = conf->nas_identifier;
15 das_conf.shared_secret = conf->radius_das_shared_secret;
16 das_conf.shared_secret_len =
17 conf->radius_das_shared_secret_len;
18 --- a/src/radius/radius_das.c
19 +++ b/src/radius/radius_das.c
21 #include "utils/common.h"
22 #include "utils/eloop.h"
23 #include "utils/ip_addr.h"
24 +#include "utils/list.h"
26 #include "radius_das.h"
29 -struct radius_das_data {
30 +static struct dl_list das_ports = DL_LIST_HEAD_INIT(das_ports);
32 +struct radius_das_port {
33 + struct dl_list list;
34 + struct dl_list das_data;
40 +struct radius_das_data {
41 + struct dl_list list;
42 + struct radius_das_port *port;
45 size_t shared_secret_len;
46 struct hostapd_ip_addr client_addr;
47 unsigned int time_window;
48 @@ -378,56 +391,17 @@ fail:
52 -static void radius_das_receive(int sock, void *eloop_ctx, void *sock_ctx)
54 +radius_das_receive_msg(struct radius_das_data *das, struct radius_msg *msg,
55 + struct sockaddr *from, socklen_t fromlen,
56 + char *abuf, int from_port)
58 - struct radius_das_data *das = eloop_ctx;
61 - struct sockaddr_storage ss;
62 - struct sockaddr_in sin;
64 - struct sockaddr_in6 sin6;
65 -#endif /* CONFIG_IPV6 */
71 - struct radius_msg *msg, *reply = NULL;
72 + struct radius_msg *reply = NULL;
73 struct radius_hdr *hdr;
80 - fromlen = sizeof(from);
81 - len = recvfrom(sock, buf, sizeof(buf), 0,
82 - (struct sockaddr *) &from.ss, &fromlen);
84 - wpa_printf(MSG_ERROR, "DAS: recvfrom: %s", strerror(errno));
88 - os_strlcpy(abuf, inet_ntoa(from.sin.sin_addr), sizeof(abuf));
89 - from_port = ntohs(from.sin.sin_port);
91 - wpa_printf(MSG_DEBUG, "DAS: Received %d bytes from %s:%d",
92 - len, abuf, from_port);
93 - if (das->client_addr.u.v4.s_addr &&
94 - das->client_addr.u.v4.s_addr != from.sin.sin_addr.s_addr) {
95 - wpa_printf(MSG_DEBUG, "DAS: Drop message from unknown client");
99 - msg = radius_msg_parse(buf, len);
101 - wpa_printf(MSG_DEBUG, "DAS: Parsing incoming RADIUS packet "
102 - "from %s:%d failed", abuf, from_port);
106 - if (wpa_debug_level <= MSG_MSGDUMP)
107 - radius_msg_dump(msg);
109 if (radius_msg_verify_das_req(msg, das->shared_secret,
110 das->shared_secret_len,
111 @@ -494,9 +468,8 @@ static void radius_das_receive(int sock,
112 radius_msg_dump(reply);
114 rbuf = radius_msg_get_buf(reply);
115 - res = sendto(das->sock, wpabuf_head(rbuf),
116 - wpabuf_len(rbuf), 0,
117 - (struct sockaddr *) &from.ss, fromlen);
118 + res = sendto(das->port->sock, wpabuf_head(rbuf),
119 + wpabuf_len(rbuf), 0, from, fromlen);
121 wpa_printf(MSG_ERROR, "DAS: sendto(to %s:%d): %s",
122 abuf, from_port, strerror(errno));
123 @@ -508,6 +481,72 @@ fail:
124 radius_msg_free(reply);
127 +static void radius_das_receive(int sock, void *eloop_ctx, void *sock_ctx)
129 + struct radius_das_port *p = eloop_ctx;
130 + struct radius_das_data *das;
133 + struct sockaddr_storage ss;
134 + struct sockaddr_in sin;
136 + struct sockaddr_in6 sin6;
137 +#endif /* CONFIG_IPV6 */
139 + struct radius_msg *msg;
140 + size_t nasid_len = 0;
141 + u8 *nasid_buf = NULL;
148 + fromlen = sizeof(from);
149 + len = recvfrom(sock, buf, sizeof(buf), 0,
150 + (struct sockaddr *) &from.ss, &fromlen);
152 + wpa_printf(MSG_ERROR, "DAS: recvfrom: %s", strerror(errno));
156 + os_strlcpy(abuf, inet_ntoa(from.sin.sin_addr), sizeof(abuf));
157 + from_port = ntohs(from.sin.sin_port);
159 + msg = radius_msg_parse(buf, len);
161 + wpa_printf(MSG_DEBUG, "DAS: Parsing incoming RADIUS packet "
162 + "from %s:%d failed", abuf, from_port);
166 + wpa_printf(MSG_DEBUG, "DAS: Received %d bytes from %s:%d",
167 + len, abuf, from_port);
169 + if (wpa_debug_level <= MSG_MSGDUMP)
170 + radius_msg_dump(msg);
172 + radius_msg_get_attr_ptr(msg, RADIUS_ATTR_NAS_IDENTIFIER,
173 + &nasid_buf, &nasid_len, NULL);
174 + dl_list_for_each(das, &p->das_data, struct radius_das_data, list) {
175 + if (das->client_addr.u.v4.s_addr &&
176 + das->client_addr.u.v4.s_addr != from.sin.sin_addr.s_addr)
179 + if (das->nas_identifier && nasid_buf &&
180 + (nasid_len != os_strlen(das->nas_identifier) ||
181 + os_memcmp(das->nas_identifier, nasid_buf, nasid_len) != 0))
185 + radius_das_receive_msg(das, msg, (struct sockaddr *)&from.ss,
186 + fromlen, abuf, from_port);
190 + wpa_printf(MSG_DEBUG, "DAS: Drop message from unknown client");
194 static int radius_das_open_socket(int port)
196 @@ -533,6 +572,49 @@ static int radius_das_open_socket(int po
200 +static struct radius_das_port *
201 +radius_das_open_port(int port)
203 + struct radius_das_port *p;
205 + dl_list_for_each(p, &das_ports, struct radius_das_port, list) {
206 + if (p->port == port)
210 + p = os_zalloc(sizeof(*p));
214 + dl_list_init(&p->das_data);
216 + p->sock = radius_das_open_socket(port);
220 + if (eloop_register_read_sock(p->sock, radius_das_receive, p, NULL))
223 + dl_list_add(&das_ports, &p->list);
235 +static void radius_das_close_port(struct radius_das_port *p)
237 + dl_list_del(&p->list);
238 + eloop_unregister_read_sock(p->sock);
243 struct radius_das_data *
244 radius_das_init(struct radius_das_conf *conf)
246 @@ -553,6 +635,8 @@ radius_das_init(struct radius_das_conf *
247 das->ctx = conf->ctx;
248 das->disconnect = conf->disconnect;
249 das->coa = conf->coa;
250 + if (conf->nas_identifier)
251 + das->nas_identifier = os_strdup(conf->nas_identifier);
253 os_memcpy(&das->client_addr, conf->client_addr,
254 sizeof(das->client_addr));
255 @@ -565,19 +649,15 @@ radius_das_init(struct radius_das_conf *
257 das->shared_secret_len = conf->shared_secret_len;
259 - das->sock = radius_das_open_socket(conf->port);
260 - if (das->sock < 0) {
261 + das->port = radius_das_open_port(conf->port);
263 wpa_printf(MSG_ERROR, "Failed to open UDP socket for RADIUS "
265 radius_das_deinit(das);
269 - if (eloop_register_read_sock(das->sock, radius_das_receive, das, NULL))
271 - radius_das_deinit(das);
274 + dl_list_add(&das->port->das_data, &das->list);
278 @@ -588,11 +668,14 @@ void radius_das_deinit(struct radius_das
282 - if (das->sock >= 0) {
283 - eloop_unregister_read_sock(das->sock);
286 + dl_list_del(&das->list);
288 + if (dl_list_empty(&das->port->das_data))
289 + radius_das_close_port(das->port);
292 + os_free(das->nas_identifier);
293 os_free(das->shared_secret);
296 --- a/src/radius/radius_das.h
297 +++ b/src/radius/radius_das.h
298 @@ -44,6 +44,7 @@ struct radius_das_attrs {
299 struct radius_das_conf {
301 const u8 *shared_secret;
302 + const u8 *nas_identifier;
303 size_t shared_secret_len;
304 const struct hostapd_ip_addr *client_addr;
305 unsigned int time_window;