[openwrt/openwrt] hostapd: allow sharing the incoming DAS port across multiple interfaces

LEDE Commits lede-commits at lists.infradead.org
Tue Dec 27 10:10:36 PST 2022


nbd pushed a commit to openwrt/openwrt.git, branch master:
https://git.openwrt.org/090ad0334369cc8c0197cd6bbb66da1eba601559

commit 090ad0334369cc8c0197cd6bbb66da1eba601559
Author: Felix Fietkau <nbd at nbd.name>
AuthorDate: Fri Dec 16 13:32:48 2022 +0100

    hostapd: allow sharing the incoming DAS port across multiple interfaces
    
    Use the NAS identifier to find the right receiver context on incoming messages
    
    Signed-off-by: Felix Fietkau <nbd at nbd.name>
---
 .../hostapd/patches/761-shared_das_port.patch      | 298 +++++++++++++++++++++
 1 file changed, 298 insertions(+)

diff --git a/package/network/services/hostapd/patches/761-shared_das_port.patch b/package/network/services/hostapd/patches/761-shared_das_port.patch
new file mode 100644
index 0000000000..7516b7349e
--- /dev/null
+++ b/package/network/services/hostapd/patches/761-shared_das_port.patch
@@ -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);
+ }




More information about the lede-commits mailing list