From e5d34da25acb59daee215ea1fb4a49338430b341 Mon Sep 17 00:00:00 2001 From: Helmut Schaa Date: Wed, 16 Sep 2015 14:04:56 +0200 Subject: [PATCH] hostapd: Force RADIUS socket renewal on RADIUS auth failures On RADIUS auth/acct failures hostapd will try a new server if one is available. Reuse the failover logic to force a socket renewal if only one RADIUS server is configured. This fixes problems when a route for the RADIUS server gets added after the socket was "connected". The RADIUS socket is still sending the RADIUS requests out using the previous route. Signed-off-by: Helmut Schaa --- src/radius/radius_client.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/radius/radius_client.c b/src/radius/radius_client.c index 693f61ea0..0bcdb4533 100644 --- a/src/radius/radius_client.c +++ b/src/radius/radius_client.c @@ -407,7 +407,6 @@ static int radius_client_retransmit(struct radius_client_data *radius, static void radius_client_timer(void *eloop_ctx, void *timeout_ctx) { struct radius_client_data *radius = eloop_ctx; - struct hostapd_radius_servers *conf = radius->conf; struct os_reltime now; os_time_t first; struct radius_msg_list *entry, *prev, *tmp; @@ -476,10 +475,10 @@ static void radius_client_timer(void *eloop_ctx, void *timeout_ctx) (long int) (first - now.sec)); } - if (auth_failover && conf->num_auth_servers > 1) + if (auth_failover) radius_client_auth_failover(radius); - if (acct_failover && conf->num_acct_servers > 1) + if (acct_failover) radius_client_acct_failover(radius); } @@ -1015,6 +1014,9 @@ radius_change_server(struct radius_client_data *radius, int sel_sock; struct radius_msg_list *entry; struct hostapd_radius_servers *conf = radius->conf; + struct sockaddr_in disconnect_addr = { + .sin_family = AF_UNSPEC, + }; hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS, HOSTAPD_LEVEL_INFO, @@ -1023,6 +1025,12 @@ radius_change_server(struct radius_client_data *radius, hostapd_ip_txt(&nserv->addr, abuf, sizeof(abuf)), nserv->port); + if (oserv && oserv == nserv) { + /* Reconnect to same server, flush */ + if (auth) + radius_client_flush(radius, 1); + } + if (oserv && oserv != nserv && (nserv->shared_secret_len != oserv->shared_secret_len || os_memcmp(nserv->shared_secret, oserv->shared_secret, @@ -1125,6 +1133,11 @@ radius_change_server(struct radius_client_data *radius, } } + /* Force a reconnect by disconnecting the socket first */ + if (connect(sel_sock, (struct sockaddr *) &disconnect_addr, + sizeof(disconnect_addr)) < 0) + wpa_printf(MSG_INFO, "disconnect[radius]: %s", strerror(errno)); + if (connect(sel_sock, addr, addrlen) < 0) { wpa_printf(MSG_INFO, "connect[radius]: %s", strerror(errno)); return -1;