]> git.ipfire.org Git - thirdparty/openwrt.git/blame - package/network/services/hostapd/patches/761-shared_das_port.patch
hostapd: adjust patches to work with git am
[thirdparty/openwrt.git] / package / network / services / hostapd / patches / 761-shared_das_port.patch
CommitLineData
92379080
EQ
1From: Felix Fietkau <nbd@nbd.name>
2Date: Fri, 16 Dec 2022 13:32:48 +0100
3Subject: [PATCH] hostapd: allow sharing the incoming DAS port across multiple
4 interfaces
5
6Use the NAS identifier to find the right receiver context on incoming messages
7
090ad033
FF
8--- a/src/ap/hostapd.c
9+++ b/src/ap/hostapd.c
24d0e746 10@@ -1510,6 +1510,7 @@ int hostapd_setup_bss(struct hostapd_dat
cd804c1e
AH
11
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;
090ad033
FF
18--- a/src/radius/radius_das.c
19+++ b/src/radius/radius_das.c
20@@ -12,13 +12,26 @@
21 #include "utils/common.h"
22 #include "utils/eloop.h"
23 #include "utils/ip_addr.h"
24+#include "utils/list.h"
25 #include "radius.h"
26 #include "radius_das.h"
27
28
29-struct radius_das_data {
30+static struct dl_list das_ports = DL_LIST_HEAD_INIT(das_ports);
31+
32+struct radius_das_port {
33+ struct dl_list list;
34+ struct dl_list das_data;
35+
36+ int port;
37 int sock;
38+};
39+
40+struct radius_das_data {
41+ struct dl_list list;
42+ struct radius_das_port *port;
43 u8 *shared_secret;
44+ u8 *nas_identifier;
45 size_t shared_secret_len;
46 struct hostapd_ip_addr client_addr;
47 unsigned int time_window;
48@@ -378,56 +391,17 @@ fail:
49 }
50
51
52-static void radius_das_receive(int sock, void *eloop_ctx, void *sock_ctx)
53+static void
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)
57 {
58- struct radius_das_data *das = eloop_ctx;
59- u8 buf[1500];
60- union {
61- struct sockaddr_storage ss;
62- struct sockaddr_in sin;
63-#ifdef CONFIG_IPV6
64- struct sockaddr_in6 sin6;
65-#endif /* CONFIG_IPV6 */
66- } from;
67- char abuf[50];
68- int from_port = 0;
69- socklen_t fromlen;
70- int len;
71- struct radius_msg *msg, *reply = NULL;
72+ struct radius_msg *reply = NULL;
73 struct radius_hdr *hdr;
74 struct wpabuf *rbuf;
75+ struct os_time now;
76 u32 val;
77 int res;
78- struct os_time now;
79-
80- fromlen = sizeof(from);
81- len = recvfrom(sock, buf, sizeof(buf), 0,
82- (struct sockaddr *) &from.ss, &fromlen);
83- if (len < 0) {
84- wpa_printf(MSG_ERROR, "DAS: recvfrom: %s", strerror(errno));
85- return;
86- }
87-
88- os_strlcpy(abuf, inet_ntoa(from.sin.sin_addr), sizeof(abuf));
89- from_port = ntohs(from.sin.sin_port);
90-
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");
96- return;
97- }
98-
99- msg = radius_msg_parse(buf, len);
100- if (msg == NULL) {
101- wpa_printf(MSG_DEBUG, "DAS: Parsing incoming RADIUS packet "
102- "from %s:%d failed", abuf, from_port);
103- return;
104- }
105-
106- if (wpa_debug_level <= MSG_MSGDUMP)
107- radius_msg_dump(msg);
108
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);
113
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);
120 if (res < 0) {
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);
125 }
126
127+static void radius_das_receive(int sock, void *eloop_ctx, void *sock_ctx)
128+{
129+ struct radius_das_port *p = eloop_ctx;
130+ struct radius_das_data *das;
131+ u8 buf[1500];
132+ union {
133+ struct sockaddr_storage ss;
134+ struct sockaddr_in sin;
135+#ifdef CONFIG_IPV6
136+ struct sockaddr_in6 sin6;
137+#endif /* CONFIG_IPV6 */
138+ } from;
139+ struct radius_msg *msg;
140+ size_t nasid_len = 0;
141+ u8 *nasid_buf = NULL;
142+ char abuf[50];
143+ int from_port = 0;
144+ socklen_t fromlen;
145+ int found = 0;
146+ int len;
147+
148+ fromlen = sizeof(from);
149+ len = recvfrom(sock, buf, sizeof(buf), 0,
150+ (struct sockaddr *) &from.ss, &fromlen);
151+ if (len < 0) {
152+ wpa_printf(MSG_ERROR, "DAS: recvfrom: %s", strerror(errno));
153+ return;
154+ }
155+
156+ os_strlcpy(abuf, inet_ntoa(from.sin.sin_addr), sizeof(abuf));
157+ from_port = ntohs(from.sin.sin_port);
158+
159+ msg = radius_msg_parse(buf, len);
160+ if (msg == NULL) {
161+ wpa_printf(MSG_DEBUG, "DAS: Parsing incoming RADIUS packet "
162+ "from %s:%d failed", abuf, from_port);
163+ return;
164+ }
165+
166+ wpa_printf(MSG_DEBUG, "DAS: Received %d bytes from %s:%d",
167+ len, abuf, from_port);
168+
169+ if (wpa_debug_level <= MSG_MSGDUMP)
170+ radius_msg_dump(msg);
171+
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)
177+ continue;
178+
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))
182+ continue;
183+
184+ found = 1;
185+ radius_das_receive_msg(das, msg, (struct sockaddr *)&from.ss,
186+ fromlen, abuf, from_port);
187+ }
188+
189+ if (!found)
190+ wpa_printf(MSG_DEBUG, "DAS: Drop message from unknown client");
191+}
192+
193
194 static int radius_das_open_socket(int port)
195 {
196@@ -533,6 +572,49 @@ static int radius_das_open_socket(int po
197 }
198
199
200+static struct radius_das_port *
201+radius_das_open_port(int port)
202+{
203+ struct radius_das_port *p;
204+
205+ dl_list_for_each(p, &das_ports, struct radius_das_port, list) {
206+ if (p->port == port)
207+ return p;
208+ }
209+
210+ p = os_zalloc(sizeof(*p));
211+ if (p == NULL)
212+ return NULL;
213+
214+ dl_list_init(&p->das_data);
215+ p->port = port;
216+ p->sock = radius_das_open_socket(port);
217+ if (p->sock < 0)
218+ goto free_port;
219+
220+ if (eloop_register_read_sock(p->sock, radius_das_receive, p, NULL))
221+ goto close_port;
222+
223+ dl_list_add(&das_ports, &p->list);
224+
225+ return p;
226+
227+close_port:
228+ close(p->sock);
229+free_port:
230+ os_free(p);
231+
232+ return NULL;
233+}
234+
235+static void radius_das_close_port(struct radius_das_port *p)
236+{
237+ dl_list_del(&p->list);
238+ eloop_unregister_read_sock(p->sock);
239+ close(p->sock);
240+ free(p);
241+}
242+
243 struct radius_das_data *
244 radius_das_init(struct radius_das_conf *conf)
245 {
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);
252
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 *
256 }
257 das->shared_secret_len = conf->shared_secret_len;
258
259- das->sock = radius_das_open_socket(conf->port);
260- if (das->sock < 0) {
261+ das->port = radius_das_open_port(conf->port);
262+ if (!das->port) {
263 wpa_printf(MSG_ERROR, "Failed to open UDP socket for RADIUS "
264 "DAS");
265 radius_das_deinit(das);
266 return NULL;
267 }
268
269- if (eloop_register_read_sock(das->sock, radius_das_receive, das, NULL))
270- {
271- radius_das_deinit(das);
272- return NULL;
273- }
274+ dl_list_add(&das->port->das_data, &das->list);
275
276 return das;
277 }
278@@ -588,11 +668,14 @@ void radius_das_deinit(struct radius_das
279 if (das == NULL)
280 return;
281
282- if (das->sock >= 0) {
283- eloop_unregister_read_sock(das->sock);
284- close(das->sock);
285+ if (das->port) {
286+ dl_list_del(&das->list);
287+
288+ if (dl_list_empty(&das->port->das_data))
289+ radius_das_close_port(das->port);
290 }
291
292+ os_free(das->nas_identifier);
293 os_free(das->shared_secret);
294 os_free(das);
295 }
92379080
EQ
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 {
300 int port;
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;