Disable network block temporarily on authentication failures
If 4-way handshake fails due to likely PSK failure or if EAP authentication fails, disable the network block temporarily. Use longer duration if multiple consecutive failures are seen. Signed-hostap: Jouni Malinen <j@w1.fi>
This commit is contained in:
parent
2af4d404a8
commit
00e5e3d509
9 changed files with 145 additions and 1 deletions
|
@ -48,6 +48,10 @@ extern "C" {
|
||||||
#define WPA_EVENT_EAP_SUCCESS "CTRL-EVENT-EAP-SUCCESS "
|
#define WPA_EVENT_EAP_SUCCESS "CTRL-EVENT-EAP-SUCCESS "
|
||||||
/** EAP authentication failed (EAP-Failure received) */
|
/** EAP authentication failed (EAP-Failure received) */
|
||||||
#define WPA_EVENT_EAP_FAILURE "CTRL-EVENT-EAP-FAILURE "
|
#define WPA_EVENT_EAP_FAILURE "CTRL-EVENT-EAP-FAILURE "
|
||||||
|
/** Network block temporarily disabled (e.g., due to authentication failure) */
|
||||||
|
#define WPA_EVENT_TEMP_DISABLED "CTRL-EVENT-SSID-TEMP-DISABLED "
|
||||||
|
/** Temporarily disabled network block re-enabled */
|
||||||
|
#define WPA_EVENT_REENABLED "CTRL-EVENT-SSID-REENABLED "
|
||||||
/** New scan results available */
|
/** New scan results available */
|
||||||
#define WPA_EVENT_SCAN_RESULTS "CTRL-EVENT-SCAN-RESULTS "
|
#define WPA_EVENT_SCAN_RESULTS "CTRL-EVENT-SCAN-RESULTS "
|
||||||
/** wpa_supplicant state change */
|
/** wpa_supplicant state change */
|
||||||
|
|
|
@ -1920,3 +1920,11 @@ void eapol_sm_set_ext_pw_ctx(struct eapol_sm *sm,
|
||||||
if (sm && sm->eap)
|
if (sm && sm->eap)
|
||||||
eap_sm_set_ext_pw_ctx(sm->eap, ext);
|
eap_sm_set_ext_pw_ctx(sm->eap, ext);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int eapol_sm_failed(struct eapol_sm *sm)
|
||||||
|
{
|
||||||
|
if (sm == NULL)
|
||||||
|
return 0;
|
||||||
|
return !sm->eapSuccess && sm->eapFail;
|
||||||
|
}
|
||||||
|
|
|
@ -278,6 +278,7 @@ void eapol_sm_invalidate_cached_session(struct eapol_sm *sm);
|
||||||
const char * eapol_sm_get_method_name(struct eapol_sm *sm);
|
const char * eapol_sm_get_method_name(struct eapol_sm *sm);
|
||||||
void eapol_sm_set_ext_pw_ctx(struct eapol_sm *sm,
|
void eapol_sm_set_ext_pw_ctx(struct eapol_sm *sm,
|
||||||
struct ext_password_data *ext);
|
struct ext_password_data *ext);
|
||||||
|
int eapol_sm_failed(struct eapol_sm *sm);
|
||||||
#else /* IEEE8021X_EAPOL */
|
#else /* IEEE8021X_EAPOL */
|
||||||
static inline struct eapol_sm *eapol_sm_init(struct eapol_ctx *ctx)
|
static inline struct eapol_sm *eapol_sm_init(struct eapol_ctx *ctx)
|
||||||
{
|
{
|
||||||
|
@ -373,6 +374,10 @@ static inline void eapol_sm_set_ext_pw_ctx(struct eapol_sm *sm,
|
||||||
struct ext_password_data *ext)
|
struct ext_password_data *ext)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
static inline int eapol_sm_failed(struct eapol_sm *sm)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
#endif /* IEEE8021X_EAPOL */
|
#endif /* IEEE8021X_EAPOL */
|
||||||
|
|
||||||
#endif /* EAPOL_SUPP_SM_H */
|
#endif /* EAPOL_SUPP_SM_H */
|
||||||
|
|
|
@ -519,6 +519,16 @@ struct wpa_ssid {
|
||||||
* By default: 2
|
* By default: 2
|
||||||
*/
|
*/
|
||||||
int dtim_period;
|
int dtim_period;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* auth_failures - Number of consecutive authentication failures
|
||||||
|
*/
|
||||||
|
unsigned int auth_failures;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* disabled_until - Network block disabled until this time if non-zero
|
||||||
|
*/
|
||||||
|
struct os_time disabled_until;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* CONFIG_SSID_H */
|
#endif /* CONFIG_SSID_H */
|
||||||
|
|
|
@ -1362,10 +1362,12 @@ static int wpa_supplicant_ctrl_iface_list_networks(
|
||||||
if (ret < 0 || ret >= end - pos)
|
if (ret < 0 || ret >= end - pos)
|
||||||
return pos - buf;
|
return pos - buf;
|
||||||
pos += ret;
|
pos += ret;
|
||||||
ret = os_snprintf(pos, end - pos, "\t%s%s%s",
|
ret = os_snprintf(pos, end - pos, "\t%s%s%s%s",
|
||||||
ssid == wpa_s->current_ssid ?
|
ssid == wpa_s->current_ssid ?
|
||||||
"[CURRENT]" : "",
|
"[CURRENT]" : "",
|
||||||
ssid->disabled ? "[DISABLED]" : "",
|
ssid->disabled ? "[DISABLED]" : "",
|
||||||
|
ssid->disabled_until.sec ?
|
||||||
|
"[TEMP-DISABLED]" : "",
|
||||||
ssid->disabled == 2 ? "[P2P-PERSISTENT]" :
|
ssid->disabled == 2 ? "[P2P-PERSISTENT]" :
|
||||||
"");
|
"");
|
||||||
if (ret < 0 || ret >= end - pos)
|
if (ret < 0 || ret >= end - pos)
|
||||||
|
|
|
@ -43,9 +43,28 @@
|
||||||
#include "offchannel.h"
|
#include "offchannel.h"
|
||||||
|
|
||||||
|
|
||||||
|
static int wpas_temp_disabled(struct wpa_supplicant *wpa_s,
|
||||||
|
struct wpa_ssid *ssid)
|
||||||
|
{
|
||||||
|
struct os_time now;
|
||||||
|
|
||||||
|
if (ssid == NULL || ssid->disabled_until.sec == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
os_get_time(&now);
|
||||||
|
if (ssid->disabled_until.sec > now.sec)
|
||||||
|
return ssid->disabled_until.sec - now.sec;
|
||||||
|
|
||||||
|
wpas_clear_temp_disabled(wpa_s, ssid, 0);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int wpa_supplicant_select_config(struct wpa_supplicant *wpa_s)
|
static int wpa_supplicant_select_config(struct wpa_supplicant *wpa_s)
|
||||||
{
|
{
|
||||||
struct wpa_ssid *ssid, *old_ssid;
|
struct wpa_ssid *ssid, *old_ssid;
|
||||||
|
int res;
|
||||||
|
|
||||||
if (wpa_s->conf->ap_scan == 1 && wpa_s->current_ssid)
|
if (wpa_s->conf->ap_scan == 1 && wpa_s->current_ssid)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -64,6 +83,13 @@ static int wpa_supplicant_select_config(struct wpa_supplicant *wpa_s)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
res = wpas_temp_disabled(wpa_s, ssid);
|
||||||
|
if (res > 0) {
|
||||||
|
wpa_dbg(wpa_s, MSG_DEBUG, "Selected network is temporarily "
|
||||||
|
"disabled for %d second(s)", res);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
wpa_dbg(wpa_s, MSG_DEBUG, "Network configuration found for the "
|
wpa_dbg(wpa_s, MSG_DEBUG, "Network configuration found for the "
|
||||||
"current AP");
|
"current AP");
|
||||||
if (wpa_key_mgmt_wpa_any(ssid->key_mgmt)) {
|
if (wpa_key_mgmt_wpa_any(ssid->key_mgmt)) {
|
||||||
|
@ -652,12 +678,20 @@ static struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
|
||||||
|
|
||||||
for (ssid = group; ssid; ssid = ssid->pnext) {
|
for (ssid = group; ssid; ssid = ssid->pnext) {
|
||||||
int check_ssid = wpa ? 1 : (ssid->ssid_len != 0);
|
int check_ssid = wpa ? 1 : (ssid->ssid_len != 0);
|
||||||
|
int res;
|
||||||
|
|
||||||
if (wpas_network_disabled(wpa_s, ssid)) {
|
if (wpas_network_disabled(wpa_s, ssid)) {
|
||||||
wpa_dbg(wpa_s, MSG_DEBUG, " skip - disabled");
|
wpa_dbg(wpa_s, MSG_DEBUG, " skip - disabled");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
res = wpas_temp_disabled(wpa_s, ssid);
|
||||||
|
if (res > 0) {
|
||||||
|
wpa_dbg(wpa_s, MSG_DEBUG, " skip - disabled "
|
||||||
|
"temporarily for %d second(s)", res);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_WPS
|
#ifdef CONFIG_WPS
|
||||||
if ((ssid->key_mgmt & WPA_KEY_MGMT_WPS) && e && e->count > 0) {
|
if ((ssid->key_mgmt & WPA_KEY_MGMT_WPS) && e && e->count > 0) {
|
||||||
wpa_dbg(wpa_s, MSG_DEBUG, " skip - blacklisted "
|
wpa_dbg(wpa_s, MSG_DEBUG, " skip - blacklisted "
|
||||||
|
@ -1735,6 +1769,7 @@ static void wpa_supplicant_event_disassoc(struct wpa_supplicant *wpa_s,
|
||||||
wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt)) {
|
wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt)) {
|
||||||
wpa_msg(wpa_s, MSG_INFO, "WPA: 4-Way Handshake failed - "
|
wpa_msg(wpa_s, MSG_INFO, "WPA: 4-Way Handshake failed - "
|
||||||
"pre-shared key may be incorrect");
|
"pre-shared key may be incorrect");
|
||||||
|
wpas_auth_failed(wpa_s);
|
||||||
}
|
}
|
||||||
if (!wpa_s->auto_reconnect_disabled ||
|
if (!wpa_s->auto_reconnect_disabled ||
|
||||||
wpa_s->key_mgmt == WPA_KEY_MGMT_WPS) {
|
wpa_s->key_mgmt == WPA_KEY_MGMT_WPS) {
|
||||||
|
@ -2306,6 +2341,11 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
|
||||||
#endif /* CONFIG_AP */
|
#endif /* CONFIG_AP */
|
||||||
wpa_supplicant_event_disassoc(wpa_s, reason_code,
|
wpa_supplicant_event_disassoc(wpa_s, reason_code,
|
||||||
locally_generated);
|
locally_generated);
|
||||||
|
if (reason_code == WLAN_REASON_IEEE_802_1X_AUTH_FAILED ||
|
||||||
|
((wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) ||
|
||||||
|
(wpa_s->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA)) &&
|
||||||
|
eapol_sm_failed(wpa_s->eapol)))
|
||||||
|
wpas_auth_failed(wpa_s);
|
||||||
#ifdef CONFIG_P2P
|
#ifdef CONFIG_P2P
|
||||||
if (event == EVENT_DEAUTH && data) {
|
if (event == EVENT_DEAUTH && data) {
|
||||||
wpas_p2p_deauth_notif(wpa_s, data->deauth_info.addr,
|
wpas_p2p_deauth_notif(wpa_s, data->deauth_info.addr,
|
||||||
|
|
|
@ -648,6 +648,7 @@ void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s,
|
||||||
ssid ? ssid->id : -1,
|
ssid ? ssid->id : -1,
|
||||||
ssid && ssid->id_str ? ssid->id_str : "");
|
ssid && ssid->id_str ? ssid->id_str : "");
|
||||||
#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
|
#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
|
||||||
|
wpas_clear_temp_disabled(wpa_s, ssid, 1);
|
||||||
wpa_s->new_connection = 0;
|
wpa_s->new_connection = 0;
|
||||||
wpa_s->reassociated_connection = 1;
|
wpa_s->reassociated_connection = 1;
|
||||||
wpa_drv_set_operstate(wpa_s, 1);
|
wpa_drv_set_operstate(wpa_s, 1);
|
||||||
|
@ -1723,6 +1724,8 @@ void wpa_supplicant_enable_network(struct wpa_supplicant *wpa_s,
|
||||||
was_disabled = other_ssid->disabled;
|
was_disabled = other_ssid->disabled;
|
||||||
|
|
||||||
other_ssid->disabled = 0;
|
other_ssid->disabled = 0;
|
||||||
|
if (was_disabled)
|
||||||
|
wpas_clear_temp_disabled(wpa_s, other_ssid, 0);
|
||||||
|
|
||||||
if (was_disabled != other_ssid->disabled)
|
if (was_disabled != other_ssid->disabled)
|
||||||
wpas_notify_network_enabled_changed(
|
wpas_notify_network_enabled_changed(
|
||||||
|
@ -1743,6 +1746,7 @@ void wpa_supplicant_enable_network(struct wpa_supplicant *wpa_s,
|
||||||
was_disabled = ssid->disabled;
|
was_disabled = ssid->disabled;
|
||||||
|
|
||||||
ssid->disabled = 0;
|
ssid->disabled = 0;
|
||||||
|
wpas_clear_temp_disabled(wpa_s, ssid, 1);
|
||||||
|
|
||||||
if (was_disabled != ssid->disabled)
|
if (was_disabled != ssid->disabled)
|
||||||
wpas_notify_network_enabled_changed(wpa_s, ssid);
|
wpas_notify_network_enabled_changed(wpa_s, ssid);
|
||||||
|
@ -1813,6 +1817,9 @@ void wpa_supplicant_select_network(struct wpa_supplicant *wpa_s,
|
||||||
disconnected = 1;
|
disconnected = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ssid)
|
||||||
|
wpas_clear_temp_disabled(wpa_s, ssid, 1);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Mark all other networks disabled or mark all networks enabled if no
|
* Mark all other networks disabled or mark all networks enabled if no
|
||||||
* network specified.
|
* network specified.
|
||||||
|
@ -1824,6 +1831,8 @@ void wpa_supplicant_select_network(struct wpa_supplicant *wpa_s,
|
||||||
continue; /* do not change persistent P2P group data */
|
continue; /* do not change persistent P2P group data */
|
||||||
|
|
||||||
other_ssid->disabled = ssid ? (ssid->id != other_ssid->id) : 0;
|
other_ssid->disabled = ssid ? (ssid->id != other_ssid->id) : 0;
|
||||||
|
if (was_disabled && !other_ssid->disabled)
|
||||||
|
wpas_clear_temp_disabled(wpa_s, other_ssid, 0);
|
||||||
|
|
||||||
if (was_disabled != other_ssid->disabled)
|
if (was_disabled != other_ssid->disabled)
|
||||||
wpas_notify_network_enabled_changed(wpa_s, other_ssid);
|
wpas_notify_network_enabled_changed(wpa_s, other_ssid);
|
||||||
|
@ -3543,3 +3552,63 @@ int wpas_is_p2p_prioritized(struct wpa_supplicant *wpa_s)
|
||||||
return 0;
|
return 0;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void wpas_auth_failed(struct wpa_supplicant *wpa_s)
|
||||||
|
{
|
||||||
|
struct wpa_ssid *ssid = wpa_s->current_ssid;
|
||||||
|
int dur;
|
||||||
|
struct os_time now;
|
||||||
|
|
||||||
|
if (ssid == NULL) {
|
||||||
|
wpa_printf(MSG_DEBUG, "Authentication failure but no known "
|
||||||
|
"SSID block");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ssid->key_mgmt == WPA_KEY_MGMT_WPS)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ssid->auth_failures++;
|
||||||
|
if (ssid->auth_failures > 50)
|
||||||
|
dur = 300;
|
||||||
|
else if (ssid->auth_failures > 20)
|
||||||
|
dur = 120;
|
||||||
|
else if (ssid->auth_failures > 10)
|
||||||
|
dur = 60;
|
||||||
|
else if (ssid->auth_failures > 5)
|
||||||
|
dur = 30;
|
||||||
|
else if (ssid->auth_failures > 1)
|
||||||
|
dur = 20;
|
||||||
|
else
|
||||||
|
dur = 10;
|
||||||
|
|
||||||
|
os_get_time(&now);
|
||||||
|
if (now.sec + dur <= ssid->disabled_until.sec)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ssid->disabled_until.sec = now.sec + dur;
|
||||||
|
|
||||||
|
wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_TEMP_DISABLED
|
||||||
|
"id=%d ssid=\"%s\" auth_failures=%u duration=%d",
|
||||||
|
ssid->id, wpa_ssid_txt(ssid->ssid, ssid->ssid_len),
|
||||||
|
ssid->auth_failures, dur);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void wpas_clear_temp_disabled(struct wpa_supplicant *wpa_s,
|
||||||
|
struct wpa_ssid *ssid, int clear_failures)
|
||||||
|
{
|
||||||
|
if (ssid == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (ssid->disabled_until.sec) {
|
||||||
|
wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_REENABLED
|
||||||
|
"id=%d ssid=\"%s\"",
|
||||||
|
ssid->id, wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
|
||||||
|
}
|
||||||
|
ssid->disabled_until.sec = 0;
|
||||||
|
ssid->disabled_until.usec = 0;
|
||||||
|
if (clear_failures)
|
||||||
|
ssid->auth_failures = 0;
|
||||||
|
}
|
||||||
|
|
|
@ -652,6 +652,9 @@ void wpa_supplicant_clear_status(struct wpa_supplicant *wpa_s);
|
||||||
void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid);
|
void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid);
|
||||||
int wpas_driver_bss_selection(struct wpa_supplicant *wpa_s);
|
int wpas_driver_bss_selection(struct wpa_supplicant *wpa_s);
|
||||||
int wpas_is_p2p_prioritized(struct wpa_supplicant *wpa_s);
|
int wpas_is_p2p_prioritized(struct wpa_supplicant *wpa_s);
|
||||||
|
void wpas_auth_failed(struct wpa_supplicant *wpa_s);
|
||||||
|
void wpas_clear_temp_disabled(struct wpa_supplicant *wpa_s,
|
||||||
|
struct wpa_ssid *ssid, int clear_failures);
|
||||||
void wpa_supplicant_proc_40mhz_intolerant(struct wpa_supplicant *wpa_s);
|
void wpa_supplicant_proc_40mhz_intolerant(struct wpa_supplicant *wpa_s);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -267,6 +267,9 @@ static int wpa_supplicant_wps_cred(void *ctx,
|
||||||
ssid->temporary = 0;
|
ssid->temporary = 0;
|
||||||
ssid->bssid_set = 0;
|
ssid->bssid_set = 0;
|
||||||
}
|
}
|
||||||
|
ssid->disabled_until.sec = 0;
|
||||||
|
ssid->disabled_until.usec = 0;
|
||||||
|
ssid->auth_failures = 0;
|
||||||
} else {
|
} else {
|
||||||
wpa_printf(MSG_DEBUG, "WPS: Create a new network based on the "
|
wpa_printf(MSG_DEBUG, "WPS: Create a new network based on the "
|
||||||
"received credential");
|
"received credential");
|
||||||
|
|
Loading…
Reference in a new issue