RADIUS client: Re-try connection if socket is closed on retransmit
Previously, send() was called with invalid fd = -1 in some error cases for retransmission and this could even result in a loop of multiple such attempts. This is obviously not going to work, so drop such attempts and instead, try to reconnect a socket to the server if the current socket is not valid. In addition, initiate server failover immediately if the current socket is not valid instead of waiting for a timeout. Signed-off-by: Jouni Malinen <j@w1.fi>
This commit is contained in:
parent
abeea374a4
commit
347c55e216
1 changed files with 74 additions and 44 deletions
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* RADIUS client
|
* RADIUS client
|
||||||
* Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
|
* Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi>
|
||||||
*
|
*
|
||||||
* This software may be distributed under the terms of the BSD license.
|
* This software may be distributed under the terms of the BSD license.
|
||||||
* See README for more details.
|
* See README for more details.
|
||||||
|
@ -236,6 +236,8 @@ radius_change_server(struct radius_client_data *radius,
|
||||||
int sock, int sock6, int auth);
|
int sock, int sock6, int auth);
|
||||||
static int radius_client_init_acct(struct radius_client_data *radius);
|
static int radius_client_init_acct(struct radius_client_data *radius);
|
||||||
static int radius_client_init_auth(struct radius_client_data *radius);
|
static int radius_client_init_auth(struct radius_client_data *radius);
|
||||||
|
static void radius_client_auth_failover(struct radius_client_data *radius);
|
||||||
|
static void radius_client_acct_failover(struct radius_client_data *radius);
|
||||||
|
|
||||||
|
|
||||||
static void radius_client_msg_free(struct radius_msg_list *req)
|
static void radius_client_msg_free(struct radius_msg_list *req)
|
||||||
|
@ -304,7 +306,7 @@ static int radius_client_handle_send_error(struct radius_client_data *radius,
|
||||||
{
|
{
|
||||||
#ifndef CONFIG_NATIVE_WINDOWS
|
#ifndef CONFIG_NATIVE_WINDOWS
|
||||||
int _errno = errno;
|
int _errno = errno;
|
||||||
wpa_printf(MSG_INFO, "send[RADIUS]: %s", strerror(errno));
|
wpa_printf(MSG_INFO, "send[RADIUS,s=%d]: %s", s, strerror(errno));
|
||||||
if (_errno == ENOTCONN || _errno == EDESTADDRREQ || _errno == EINVAL ||
|
if (_errno == ENOTCONN || _errno == EDESTADDRREQ || _errno == EINVAL ||
|
||||||
_errno == EBADF || _errno == ENETUNREACH) {
|
_errno == EBADF || _errno == ENETUNREACH) {
|
||||||
hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
|
hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
|
||||||
|
@ -336,6 +338,10 @@ static int radius_client_retransmit(struct radius_client_data *radius,
|
||||||
|
|
||||||
if (entry->msg_type == RADIUS_ACCT ||
|
if (entry->msg_type == RADIUS_ACCT ||
|
||||||
entry->msg_type == RADIUS_ACCT_INTERIM) {
|
entry->msg_type == RADIUS_ACCT_INTERIM) {
|
||||||
|
if (radius->acct_sock < 0)
|
||||||
|
radius_client_init_acct(radius);
|
||||||
|
if (radius->acct_sock < 0 && conf->num_acct_servers > 1)
|
||||||
|
radius_client_auth_failover(radius);
|
||||||
s = radius->acct_sock;
|
s = radius->acct_sock;
|
||||||
if (entry->attempts == 0)
|
if (entry->attempts == 0)
|
||||||
conf->acct_server->requests++;
|
conf->acct_server->requests++;
|
||||||
|
@ -344,6 +350,10 @@ static int radius_client_retransmit(struct radius_client_data *radius,
|
||||||
conf->acct_server->retransmissions++;
|
conf->acct_server->retransmissions++;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
if (radius->auth_sock < 0)
|
||||||
|
radius_client_init_auth(radius);
|
||||||
|
if (radius->auth_sock < 0 && conf->num_auth_servers > 1)
|
||||||
|
radius_client_auth_failover(radius);
|
||||||
s = radius->auth_sock;
|
s = radius->auth_sock;
|
||||||
if (entry->attempts == 0)
|
if (entry->attempts == 0)
|
||||||
conf->auth_server->requests++;
|
conf->auth_server->requests++;
|
||||||
|
@ -352,6 +362,11 @@ static int radius_client_retransmit(struct radius_client_data *radius,
|
||||||
conf->auth_server->retransmissions++;
|
conf->auth_server->retransmissions++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (s < 0) {
|
||||||
|
wpa_printf(MSG_INFO,
|
||||||
|
"RADIUS: No valid socket for retransmission");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
/* retransmit; remove entry if too many attempts */
|
/* retransmit; remove entry if too many attempts */
|
||||||
entry->attempts++;
|
entry->attempts++;
|
||||||
|
@ -388,7 +403,6 @@ static void radius_client_timer(void *eloop_ctx, void *timeout_ctx)
|
||||||
os_time_t first;
|
os_time_t first;
|
||||||
struct radius_msg_list *entry, *prev, *tmp;
|
struct radius_msg_list *entry, *prev, *tmp;
|
||||||
int auth_failover = 0, acct_failover = 0;
|
int auth_failover = 0, acct_failover = 0;
|
||||||
char abuf[50];
|
|
||||||
size_t prev_num_msgs;
|
size_t prev_num_msgs;
|
||||||
int s;
|
int s;
|
||||||
|
|
||||||
|
@ -453,54 +467,70 @@ static void radius_client_timer(void *eloop_ctx, void *timeout_ctx)
|
||||||
(long int) (first - now.sec));
|
(long int) (first - now.sec));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auth_failover && conf->num_auth_servers > 1) {
|
if (auth_failover && conf->num_auth_servers > 1)
|
||||||
struct hostapd_radius_server *next, *old;
|
radius_client_auth_failover(radius);
|
||||||
old = conf->auth_server;
|
|
||||||
hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
|
|
||||||
HOSTAPD_LEVEL_NOTICE,
|
|
||||||
"No response from Authentication server "
|
|
||||||
"%s:%d - failover",
|
|
||||||
hostapd_ip_txt(&old->addr, abuf, sizeof(abuf)),
|
|
||||||
old->port);
|
|
||||||
|
|
||||||
for (entry = radius->msgs; entry; entry = entry->next) {
|
if (acct_failover && conf->num_acct_servers > 1)
|
||||||
if (entry->msg_type == RADIUS_AUTH)
|
radius_client_acct_failover(radius);
|
||||||
old->timeouts++;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
next = old + 1;
|
|
||||||
if (next > &(conf->auth_servers[conf->num_auth_servers - 1]))
|
static void radius_client_auth_failover(struct radius_client_data *radius)
|
||||||
next = conf->auth_servers;
|
{
|
||||||
conf->auth_server = next;
|
struct hostapd_radius_servers *conf = radius->conf;
|
||||||
radius_change_server(radius, next, old,
|
struct hostapd_radius_server *next, *old;
|
||||||
radius->auth_serv_sock,
|
struct radius_msg_list *entry;
|
||||||
radius->auth_serv_sock6, 1);
|
char abuf[50];
|
||||||
|
|
||||||
|
old = conf->auth_server;
|
||||||
|
hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
|
||||||
|
HOSTAPD_LEVEL_NOTICE,
|
||||||
|
"No response from Authentication server %s:%d - failover",
|
||||||
|
hostapd_ip_txt(&old->addr, abuf, sizeof(abuf)),
|
||||||
|
old->port);
|
||||||
|
|
||||||
|
for (entry = radius->msgs; entry; entry = entry->next) {
|
||||||
|
if (entry->msg_type == RADIUS_AUTH)
|
||||||
|
old->timeouts++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (acct_failover && conf->num_acct_servers > 1) {
|
next = old + 1;
|
||||||
struct hostapd_radius_server *next, *old;
|
if (next > &(conf->auth_servers[conf->num_auth_servers - 1]))
|
||||||
old = conf->acct_server;
|
next = conf->auth_servers;
|
||||||
hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
|
conf->auth_server = next;
|
||||||
HOSTAPD_LEVEL_NOTICE,
|
radius_change_server(radius, next, old,
|
||||||
"No response from Accounting server "
|
radius->auth_serv_sock,
|
||||||
"%s:%d - failover",
|
radius->auth_serv_sock6, 1);
|
||||||
hostapd_ip_txt(&old->addr, abuf, sizeof(abuf)),
|
}
|
||||||
old->port);
|
|
||||||
|
|
||||||
for (entry = radius->msgs; entry; entry = entry->next) {
|
|
||||||
if (entry->msg_type == RADIUS_ACCT ||
|
|
||||||
entry->msg_type == RADIUS_ACCT_INTERIM)
|
|
||||||
old->timeouts++;
|
|
||||||
}
|
|
||||||
|
|
||||||
next = old + 1;
|
static void radius_client_acct_failover(struct radius_client_data *radius)
|
||||||
if (next > &conf->acct_servers[conf->num_acct_servers - 1])
|
{
|
||||||
next = conf->acct_servers;
|
struct hostapd_radius_servers *conf = radius->conf;
|
||||||
conf->acct_server = next;
|
struct hostapd_radius_server *next, *old;
|
||||||
radius_change_server(radius, next, old,
|
struct radius_msg_list *entry;
|
||||||
radius->acct_serv_sock,
|
char abuf[50];
|
||||||
radius->acct_serv_sock6, 0);
|
|
||||||
|
old = conf->acct_server;
|
||||||
|
hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
|
||||||
|
HOSTAPD_LEVEL_NOTICE,
|
||||||
|
"No response from Accounting server %s:%d - failover",
|
||||||
|
hostapd_ip_txt(&old->addr, abuf, sizeof(abuf)),
|
||||||
|
old->port);
|
||||||
|
|
||||||
|
for (entry = radius->msgs; entry; entry = entry->next) {
|
||||||
|
if (entry->msg_type == RADIUS_ACCT ||
|
||||||
|
entry->msg_type == RADIUS_ACCT_INTERIM)
|
||||||
|
old->timeouts++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
next = old + 1;
|
||||||
|
if (next > &conf->acct_servers[conf->num_acct_servers - 1])
|
||||||
|
next = conf->acct_servers;
|
||||||
|
conf->acct_server = next;
|
||||||
|
radius_change_server(radius, next, old,
|
||||||
|
radius->acct_serv_sock,
|
||||||
|
radius->acct_serv_sock6, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue