Browse Source

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 <helmut.schaa@googlemail.com>
Helmut Schaa 9 years ago
parent
commit
e5d34da25a
1 changed files with 16 additions and 3 deletions
  1. 16 3
      src/radius/radius_client.c

+ 16 - 3
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;