mirror of
https://github.com/vanhoefm/fragattacks.git
synced 2024-11-25 08:48:31 -05:00
RADIUS: Update full message for interim accounting updates
Instead of using the RADIUS client retransmission design with the old RADIUS message contents for each retry, trigger a completely new interim accounting update instance more quickly (using the same schedule as RADIUS message retransmissions) to improve accounting updates in cases where RADIUS message delivery fails. This allows the server to get up to date information from the time the "retry" message was sent instead of the old information from the time the first failed attempt was sent. Signed-off-by: Jouni Malinen <j@w1.fi>
This commit is contained in:
parent
251953bcb6
commit
669b5324e1
@ -450,6 +450,63 @@ static void accounting_report_state(struct hostapd_data *hapd, int on)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void accounting_interim_error_cb(const u8 *addr, void *ctx)
|
||||||
|
{
|
||||||
|
struct hostapd_data *hapd = ctx;
|
||||||
|
struct sta_info *sta;
|
||||||
|
unsigned int i, wait_time;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
sta = ap_get_sta(hapd, addr);
|
||||||
|
if (!sta)
|
||||||
|
return;
|
||||||
|
sta->acct_interim_errors++;
|
||||||
|
if (sta->acct_interim_errors > 10 /* RADIUS_CLIENT_MAX_RETRIES */) {
|
||||||
|
wpa_printf(MSG_DEBUG,
|
||||||
|
"Interim RADIUS accounting update failed for " MACSTR
|
||||||
|
" - too many errors, abandon this interim accounting update",
|
||||||
|
MAC2STR(addr));
|
||||||
|
sta->acct_interim_errors = 0;
|
||||||
|
/* Next update will be tried after normal update interval */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Use a shorter update interval as an improved retransmission mechanism
|
||||||
|
* for failed interim accounting updates. This allows the statistics to
|
||||||
|
* be updated for each retransmission.
|
||||||
|
*
|
||||||
|
* RADIUS client code has already waited RADIUS_CLIENT_FIRST_WAIT.
|
||||||
|
* Schedule the first retry attempt immediately and every following one
|
||||||
|
* with exponential backoff.
|
||||||
|
*/
|
||||||
|
if (sta->acct_interim_errors == 1) {
|
||||||
|
wait_time = 0;
|
||||||
|
} else {
|
||||||
|
wait_time = 3; /* RADIUS_CLIENT_FIRST_WAIT */
|
||||||
|
for (i = 1; i < sta->acct_interim_errors; i++)
|
||||||
|
wait_time *= 2;
|
||||||
|
}
|
||||||
|
res = eloop_deplete_timeout(wait_time, 0, accounting_interim_update,
|
||||||
|
hapd, sta);
|
||||||
|
if (res == 1)
|
||||||
|
wpa_printf(MSG_DEBUG,
|
||||||
|
"Interim RADIUS accounting update failed for " MACSTR
|
||||||
|
" (error count: %u) - schedule next update in %u seconds",
|
||||||
|
MAC2STR(addr), sta->acct_interim_errors, wait_time);
|
||||||
|
else if (res == 0)
|
||||||
|
wpa_printf(MSG_DEBUG,
|
||||||
|
"Interim RADIUS accounting update failed for " MACSTR
|
||||||
|
" (error count: %u)", MAC2STR(addr),
|
||||||
|
sta->acct_interim_errors);
|
||||||
|
else
|
||||||
|
wpa_printf(MSG_DEBUG,
|
||||||
|
"Interim RADIUS accounting update failed for " MACSTR
|
||||||
|
" (error count: %u) - no timer found", MAC2STR(addr),
|
||||||
|
sta->acct_interim_errors);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* accounting_init: Initialize accounting
|
* accounting_init: Initialize accounting
|
||||||
* @hapd: hostapd BSS data
|
* @hapd: hostapd BSS data
|
||||||
@ -464,6 +521,8 @@ int accounting_init(struct hostapd_data *hapd)
|
|||||||
if (radius_client_register(hapd->radius, RADIUS_ACCT,
|
if (radius_client_register(hapd->radius, RADIUS_ACCT,
|
||||||
accounting_receive, hapd))
|
accounting_receive, hapd))
|
||||||
return -1;
|
return -1;
|
||||||
|
radius_client_set_interim_error_cb(hapd->radius,
|
||||||
|
accounting_interim_error_cb, hapd);
|
||||||
|
|
||||||
accounting_report_state(hapd, 1);
|
accounting_report_state(hapd, 1);
|
||||||
|
|
||||||
|
@ -118,6 +118,7 @@ struct sta_info {
|
|||||||
int acct_session_started;
|
int acct_session_started;
|
||||||
int acct_terminate_cause; /* Acct-Terminate-Cause */
|
int acct_terminate_cause; /* Acct-Terminate-Cause */
|
||||||
int acct_interim_interval; /* Acct-Interim-Interval */
|
int acct_interim_interval; /* Acct-Interim-Interval */
|
||||||
|
unsigned int acct_interim_errors;
|
||||||
|
|
||||||
/* For extending 32-bit driver counters to 64-bit counters */
|
/* For extending 32-bit driver counters to 64-bit counters */
|
||||||
u32 last_rx_bytes_hi;
|
u32 last_rx_bytes_hi;
|
||||||
|
@ -226,6 +226,16 @@ struct radius_client_data {
|
|||||||
* next_radius_identifier - Next RADIUS message identifier to use
|
* next_radius_identifier - Next RADIUS message identifier to use
|
||||||
*/
|
*/
|
||||||
u8 next_radius_identifier;
|
u8 next_radius_identifier;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* interim_error_cb - Interim accounting error callback
|
||||||
|
*/
|
||||||
|
void (*interim_error_cb)(const u8 *addr, void *ctx);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* interim_error_cb_ctx - interim_error_cb() context data
|
||||||
|
*/
|
||||||
|
void *interim_error_cb_ctx;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -297,6 +307,25 @@ int radius_client_register(struct radius_client_data *radius,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* radius_client_set_interim_erro_cb - Register an interim acct error callback
|
||||||
|
* @radius: RADIUS client context from radius_client_init()
|
||||||
|
* @addr: Station address from the failed message
|
||||||
|
* @cb: Handler for interim accounting errors
|
||||||
|
* @ctx: Context pointer for handler callbacks
|
||||||
|
*
|
||||||
|
* This function is used to register a handler for processing failed
|
||||||
|
* transmission attempts of interim accounting update messages.
|
||||||
|
*/
|
||||||
|
void radius_client_set_interim_error_cb(struct radius_client_data *radius,
|
||||||
|
void (*cb)(const u8 *addr, void *ctx),
|
||||||
|
void *ctx)
|
||||||
|
{
|
||||||
|
radius->interim_error_cb = cb;
|
||||||
|
radius->interim_error_cb_ctx = ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Returns >0 if message queue was flushed (i.e., the message that triggered
|
* Returns >0 if message queue was flushed (i.e., the message that triggered
|
||||||
* the error is not available anymore)
|
* the error is not available anymore)
|
||||||
@ -371,6 +400,18 @@ static int radius_client_retransmit(struct radius_client_data *radius,
|
|||||||
conf->auth_server->retransmissions++;
|
conf->auth_server->retransmissions++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (entry->msg_type == RADIUS_ACCT_INTERIM) {
|
||||||
|
wpa_printf(MSG_DEBUG,
|
||||||
|
"RADIUS: Failed to transmit interim accounting update to "
|
||||||
|
MACSTR " - drop message and request a new update",
|
||||||
|
MAC2STR(entry->addr));
|
||||||
|
if (radius->interim_error_cb)
|
||||||
|
radius->interim_error_cb(entry->addr,
|
||||||
|
radius->interim_error_cb_ctx);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
if (s < 0) {
|
if (s < 0) {
|
||||||
wpa_printf(MSG_INFO,
|
wpa_printf(MSG_INFO,
|
||||||
"RADIUS: No valid socket for retransmission");
|
"RADIUS: No valid socket for retransmission");
|
||||||
@ -624,39 +665,6 @@ static void radius_client_list_add(struct radius_client_data *radius,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void radius_client_list_del(struct radius_client_data *radius,
|
|
||||||
RadiusType msg_type, const u8 *addr)
|
|
||||||
{
|
|
||||||
struct radius_msg_list *entry, *prev, *tmp;
|
|
||||||
|
|
||||||
if (addr == NULL)
|
|
||||||
return;
|
|
||||||
|
|
||||||
entry = radius->msgs;
|
|
||||||
prev = NULL;
|
|
||||||
while (entry) {
|
|
||||||
if (entry->msg_type == msg_type &&
|
|
||||||
os_memcmp(entry->addr, addr, ETH_ALEN) == 0) {
|
|
||||||
if (prev)
|
|
||||||
prev->next = entry->next;
|
|
||||||
else
|
|
||||||
radius->msgs = entry->next;
|
|
||||||
tmp = entry;
|
|
||||||
entry = entry->next;
|
|
||||||
hostapd_logger(radius->ctx, addr,
|
|
||||||
HOSTAPD_MODULE_RADIUS,
|
|
||||||
HOSTAPD_LEVEL_DEBUG,
|
|
||||||
"Removing matching RADIUS message");
|
|
||||||
radius_client_msg_free(tmp);
|
|
||||||
radius->num_msgs--;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
prev = entry;
|
|
||||||
entry = entry->next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* radius_client_send - Send a RADIUS request
|
* radius_client_send - Send a RADIUS request
|
||||||
* @radius: RADIUS client context from radius_client_init()
|
* @radius: RADIUS client context from radius_client_init()
|
||||||
@ -668,16 +676,19 @@ static void radius_client_list_del(struct radius_client_data *radius,
|
|||||||
* This function is used to transmit a RADIUS authentication (RADIUS_AUTH) or
|
* This function is used to transmit a RADIUS authentication (RADIUS_AUTH) or
|
||||||
* accounting request (RADIUS_ACCT or RADIUS_ACCT_INTERIM). The only difference
|
* accounting request (RADIUS_ACCT or RADIUS_ACCT_INTERIM). The only difference
|
||||||
* between accounting and interim accounting messages is that the interim
|
* between accounting and interim accounting messages is that the interim
|
||||||
* message will override any pending interim accounting updates while a new
|
* message will not be retransmitted. Instead, a callback is used to indicate
|
||||||
* accounting message does not remove any pending messages.
|
* that the transmission failed for the specific station @addr so that a new
|
||||||
|
* interim accounting update message can be generated with up-to-date session
|
||||||
|
* data instead of trying to resend old information.
|
||||||
*
|
*
|
||||||
* The message is added on the retransmission queue and will be retransmitted
|
* The message is added on the retransmission queue and will be retransmitted
|
||||||
* automatically until a response is received or maximum number of retries
|
* automatically until a response is received or maximum number of retries
|
||||||
* (RADIUS_CLIENT_MAX_RETRIES) is reached.
|
* (RADIUS_CLIENT_MAX_RETRIES) is reached. No such retries are used with
|
||||||
|
* RADIUS_ACCT_INTERIM, i.e., such a pending message is removed from the queue
|
||||||
|
* automatically on transmission failure.
|
||||||
*
|
*
|
||||||
* The related device MAC address can be used to identify pending messages that
|
* The related device MAC address can be used to identify pending messages that
|
||||||
* can be removed with radius_client_flush_auth() or with interim accounting
|
* can be removed with radius_client_flush_auth().
|
||||||
* updates.
|
|
||||||
*/
|
*/
|
||||||
int radius_client_send(struct radius_client_data *radius,
|
int radius_client_send(struct radius_client_data *radius,
|
||||||
struct radius_msg *msg, RadiusType msg_type,
|
struct radius_msg *msg, RadiusType msg_type,
|
||||||
@ -690,11 +701,6 @@ int radius_client_send(struct radius_client_data *radius,
|
|||||||
int s, res;
|
int s, res;
|
||||||
struct wpabuf *buf;
|
struct wpabuf *buf;
|
||||||
|
|
||||||
if (msg_type == RADIUS_ACCT_INTERIM) {
|
|
||||||
/* Remove any pending interim acct update for the same STA. */
|
|
||||||
radius_client_list_del(radius, msg_type, addr);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (msg_type == RADIUS_ACCT || msg_type == RADIUS_ACCT_INTERIM) {
|
if (msg_type == RADIUS_ACCT || msg_type == RADIUS_ACCT_INTERIM) {
|
||||||
if (conf->acct_server && radius->acct_sock < 0)
|
if (conf->acct_server && radius->acct_sock < 0)
|
||||||
radius_client_init_acct(radius);
|
radius_client_init_acct(radius);
|
||||||
|
@ -241,6 +241,9 @@ int radius_client_register(struct radius_client_data *radius,
|
|||||||
const u8 *shared_secret, size_t shared_secret_len,
|
const u8 *shared_secret, size_t shared_secret_len,
|
||||||
void *data),
|
void *data),
|
||||||
void *data);
|
void *data);
|
||||||
|
void radius_client_set_interim_error_cb(struct radius_client_data *radius,
|
||||||
|
void (*cb)(const u8 *addr, void *ctx),
|
||||||
|
void *ctx);
|
||||||
int radius_client_send(struct radius_client_data *radius,
|
int radius_client_send(struct radius_client_data *radius,
|
||||||
struct radius_msg *msg,
|
struct radius_msg *msg,
|
||||||
RadiusType msg_type, const u8 *addr);
|
RadiusType msg_type, const u8 *addr);
|
||||||
|
Loading…
Reference in New Issue
Block a user