|
|
@@ -0,0 +1,298 @@
|
|
|
+--- 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;
|
|
|
+--- a/src/ap/hostapd.c
|
|
|
++++ b/src/ap/hostapd.c
|
|
|
+@@ -1367,6 +1367,7 @@ static int hostapd_setup_bss(struct host
|
|
|
+ struct radius_das_conf das_conf;
|
|
|
+ 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;
|
|
|
+@@ -378,56 +391,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,
|
|
|
+@@ -494,9 +468,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));
|
|
|
+@@ -508,6 +481,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)
|
|
|
+ {
|
|
|
+@@ -533,6 +572,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)
|
|
|
+ {
|
|
|
+@@ -553,6 +635,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));
|
|
|
+@@ -565,19 +649,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;
|
|
|
+ }
|
|
|
+@@ -588,11 +668,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);
|
|
|
+ }
|