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