This patch implements hostapd-based client station blacklisting. It includes new CLI commands to add, remove, clear, and show the blacklist. Client stations in the blacklist will be denied authentication, association, and re-association with the AP. The AP will not respond to probe requests from clients in the blacklist.
From 709f5fdc2cf5bcb4660389fbe291192c349e9c9d Mon Sep 17 00:00:00 2001 From: David Weidenkopf <dweidenkopf@xxxxxxxxxxxx> Date: Thu, 7 Jul 2016 14:11:43 -0700 Subject: [PATCH] WNM: hostapd client station blacklist support. New CLI commands to add, remove, clear, and show the blacklist. Signed-off-by: Henry M. Bennett <hbennett@xxxxxxxxxxxx> Signed-off-by: Alexis Green <agreen@xxxxxxxxxxxx> Signed-off-by: David Weidenkopf <dweidenkopf@xxxxxxxxxxxx> --- hostapd/Makefile | 2 +- hostapd/ctrl_iface.c | 18 +++++++ hostapd/hostapd_cli.c | 72 ++++++++++++++++++++++++- src/ap/beacon.c | 6 +++ src/ap/ctrl_iface_ap.c | 65 ++++++++++++++++++++++- src/ap/ctrl_iface_ap.h | 8 ++- src/ap/hostapd.c | 1 + src/ap/hostapd.h | 3 ++ src/ap/ieee802_11.c | 12 ++++- src/ap/sta_blacklist.c | 140 +++++++++++++++++++++++++++++++++++++++++++++++++ src/ap/sta_blacklist.h | 14 +++++ 11 files changed, 335 insertions(+), 6 deletions(-) create mode 100644 src/ap/sta_blacklist.c create mode 100644 src/ap/sta_blacklist.h diff --git a/hostapd/Makefile b/hostapd/Makefile index baa7819..2d0bdc2 100644 --- a/hostapd/Makefile +++ b/hostapd/Makefile @@ -63,7 +63,6 @@ endif OBJS += main.o OBJS += config_file.o - OBJS += ../src/ap/hostapd.o OBJS += ../src/ap/wpa_auth_glue.o OBJS += ../src/ap/drv_callbacks.o @@ -86,6 +85,7 @@ OBJS += ../src/ap/beacon.o OBJS += ../src/ap/bss_load.o OBJS += ../src/ap/neighbor_db.o OBJS += ../src/ap/rrm.o +OBJS += ../src/ap/sta_blacklist.o OBJS_c = hostapd_cli.o ../src/common/wpa_ctrl.o ../src/utils/os_$(CONFIG_OS).o diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c index 62bef18..d037d3d 100644 --- a/hostapd/ctrl_iface.c +++ b/hostapd/ctrl_iface.c @@ -2488,6 +2488,24 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd, } else if (os_strncmp(buf, "LOG_LEVEL", 9) == 0) { reply_len = hostapd_ctrl_iface_log_level( hapd, buf + 9, reply, reply_size); + /* BEGIN HOSTAPD BLACKLIST SUPPORT */ + } else if (os_strncmp(buf, "BLACKLIST_ADD ", 14) == 0) { + if (hostapd_ctrl_iface_blacklist_add(hapd, buf + 14)) + reply_len = -1; + } else if (os_strncmp(buf, "BLACKLIST_RM ", 13) == 0) { + if (hostapd_ctrl_iface_blacklist_rm(hapd, buf + 13)) + reply_len = -1; + } else if (os_strcmp(buf, "BLACKLIST_SHOW") == 0) { + reply_len = hostapd_ctrl_iface_blacklist_show(hapd, reply, + reply_size); + if(reply_len == 0) { + os_memcpy(reply, "EMPTY\n", 6); + reply_len = 6; + } + } else if (os_strcmp(buf, "BLACKLIST_CLR") == 0) { + if(hostapd_ctrl_iface_blacklist_clr(hapd)) + reply_len = -1; + /* END HOSTAPD BLACKLIST SUPPORT */ #ifdef NEED_AP_MLME } else if (os_strcmp(buf, "TRACK_STA_LIST") == 0) { reply_len = hostapd_ctrl_iface_track_sta_list( diff --git a/hostapd/hostapd_cli.c b/hostapd/hostapd_cli.c index ff133f6..ce6aecf 100644 --- a/hostapd/hostapd_cli.c +++ b/hostapd/hostapd_cli.c @@ -65,6 +65,11 @@ static const char *const commands_help = " all_sta get MIB variables for all stations\n" " new_sta <addr> add a new station\n" " deauthenticate <addr> deauthenticate a station\n" +" blacklist_add <addr> blacklist a station from an AP\n" +" blacklist_rm <addr> remove a station from the blacklist\n" +" blacklist_clr clear all stations from the blacklist\n" +" blacklist_show show entire blacklist\n" +" bss_transition <addr> <beacon timer count> <AP addr> <AP channel> disassociate a WNM station telling the station which AP to connect to\n" " disassociate <addr> disassociate a station\n" #ifdef CONFIG_IEEE80211W " sa_query <addr> send SA Query to a station\n" @@ -351,7 +356,6 @@ static int hostapd_cli_cmd_sta(struct wpa_ctrl *ctrl, int argc, char *argv[]) return wpa_ctrl_command(ctrl, buf); } - static int hostapd_cli_cmd_new_sta(struct wpa_ctrl *ctrl, int argc, char *argv[]) { @@ -366,6 +370,65 @@ static int hostapd_cli_cmd_new_sta(struct wpa_ctrl *ctrl, int argc, } +/* BEGIN HOSTAPD BLACKLIST SUPPORT */ +static int hostapd_cli_cmd_blacklist_add_hostapd(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + char buf[64]; + + if (argc != 1) { + printf("Invalid 'blacklist_add_hostapd' command - exactly one argument, STA address, is required.\n"); + return -1; + } + + os_snprintf(buf, sizeof(buf), "BLACKLIST_ADD %s", argv[0]); + return wpa_ctrl_command(ctrl, buf); +} + +static int hostapd_cli_cmd_blacklist_rm_hostapd(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + char buf[64]; + + if (argc != 1) { + printf("Invalid 'blacklist_rm_hostapd' command - exactly one argument, STA address, is required.\n"); + return -1; + } + + os_snprintf(buf, sizeof(buf), "BLACKLIST_RM %s", argv[0]); + return wpa_ctrl_command(ctrl, buf); +} + +static int hostapd_cli_cmd_blacklist_show(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + char buf[64]; + + if (argc > 0) { + printf("Invalid 'blacklist_show' command - this command takes no arguments.\n"); + return -1; + } + + os_snprintf(buf, sizeof(buf), "BLACKLIST_SHOW"); + return wpa_ctrl_command(ctrl, buf); +} + +static int hostapd_cli_cmd_blacklist_clr_hostapd(struct wpa_ctrl *ctrl, int argc, + char *argv[]) +{ + char buf[64]; + + if (argc != 0) { + printf("Invalid 'blacklist_add_hostapd' command - exactly zero arguments is required.\n"); + return -1; + } + + os_snprintf(buf, sizeof(buf), "BLACKLIST_CLR"); + return wpa_ctrl_command(ctrl, buf); +} + +/* END HOSTAPD BLACKLIST SUPPORT */ + static int hostapd_cli_cmd_deauthenticate(struct wpa_ctrl *ctrl, int argc, char *argv[]) { @@ -1102,7 +1165,6 @@ static int hostapd_cli_cmd_erp_flush(struct wpa_ctrl *ctrl, int argc, return wpa_ctrl_command(ctrl, "ERP_FLUSH"); } - static int hostapd_cli_cmd_log_level(struct wpa_ctrl *ctrl, int argc, char *argv[]) { @@ -1233,6 +1295,12 @@ static const struct hostapd_cli_cmd hostapd_cli_commands[] = { { "new_sta", hostapd_cli_cmd_new_sta }, { "deauthenticate", hostapd_cli_cmd_deauthenticate }, { "disassociate", hostapd_cli_cmd_disassociate }, + + { "blacklist_add", hostapd_cli_cmd_blacklist_add_hostapd }, + { "blacklist_rm", hostapd_cli_cmd_blacklist_rm_hostapd }, + { "blacklist_show", hostapd_cli_cmd_blacklist_show }, + { "blacklist_clr", hostapd_cli_cmd_blacklist_clr_hostapd }, + #ifdef CONFIG_IEEE80211W { "sa_query", hostapd_cli_cmd_sa_query }, #endif /* CONFIG_IEEE80211W */ diff --git a/src/ap/beacon.c b/src/ap/beacon.c index 0570ab7..c4a84a4 100644 --- a/src/ap/beacon.c +++ b/src/ap/beacon.c @@ -29,6 +29,7 @@ #include "beacon.h" #include "hs20.h" #include "dfs.h" +#include "sta_blacklist.h" #ifdef NEED_AP_MLME @@ -838,6 +839,11 @@ void handle_probe_req(struct hostapd_data *hapd, } #endif /* CONFIG_P2P */ + if(sta_blacklist_present(hapd, mgmt->sa)) { + wpa_printf(MSG_DEBUG, "ignoring probe request from " MACSTR " due to blacklist", MAC2STR(mgmt->sa)); + return; + } + /* TODO: verify that supp_rates contains at least one matching rate * with AP configuration */ diff --git a/src/ap/ctrl_iface_ap.c b/src/ap/ctrl_iface_ap.c index 14c154f..d340269 100644 --- a/src/ap/ctrl_iface_ap.c +++ b/src/ap/ctrl_iface_ap.c @@ -23,7 +23,7 @@ #include "ctrl_iface_ap.h" #include "ap_drv_ops.h" #include "mbo_ap.h" - +#include "sta_blacklist.h" static int hostapd_get_sta_tx_rx(struct hostapd_data *hapd, struct sta_info *sta, @@ -550,6 +550,69 @@ int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf, return len; } +int hostapd_ctrl_iface_blacklist_add(struct hostapd_data *hapd, + const char *txtaddr) +{ + u8 addr[ETH_ALEN]; + int ret = -1; + + wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE BLACKLIST_ADD %s", + txtaddr); + + if (hwaddr_aton(txtaddr, addr)) + return -1; + + ret = sta_blacklist_add(hapd, addr); + + return ret; +} + +int hostapd_ctrl_iface_blacklist_rm(struct hostapd_data *hapd, + const char *txtaddr) +{ + u8 addr[ETH_ALEN]; + int ret = -1; + + wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE BLACKLIST_RM %s", + txtaddr); + + if (hwaddr_aton(txtaddr, addr)) + return -1; + + ret = sta_blacklist_rm(hapd, addr); + + return ret; +} + +int hostapd_ctrl_iface_blacklist_show(struct hostapd_data *hapd, char *buf, + size_t buflen) +{ + int len = 0, ret = 0; + struct sta_blacklist *e = hapd->blacklist; + + while (e) { + ret = os_snprintf(buf + len, buflen - len, + MACSTR "\n", + MAC2STR(e->sta)); + if (ret < 0 || (size_t) ret >= buflen - len) + return len; + len += ret; + e = e->next; + } + + return ret; +} + +int hostapd_ctrl_iface_blacklist_clr(struct hostapd_data *hapd) +{ + int ret = -1; + + wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE BLACKLIST_CLR"); + + ret = sta_blacklist_clear(hapd); + + return ret; +} int hostapd_parse_csa_settings(const char *pos, struct csa_settings *settings) diff --git a/src/ap/ctrl_iface_ap.h b/src/ap/ctrl_iface_ap.h index 6095d7d..346c6f3 100644 --- a/src/ap/ctrl_iface_ap.h +++ b/src/ap/ctrl_iface_ap.h @@ -29,5 +29,11 @@ int hostapd_ctrl_iface_stop_ap(struct hostapd_data *hapd); int hostapd_ctrl_iface_pmksa_list(struct hostapd_data *hapd, char *buf, size_t len); void hostapd_ctrl_iface_pmksa_flush(struct hostapd_data *hapd); - +int hostapd_ctrl_iface_blacklist_add(struct hostapd_data *hapd, + const char *txtaddr); +int hostapd_ctrl_iface_blacklist_rm(struct hostapd_data *hapd, + const char *txtaddr); +int hostapd_ctrl_iface_blacklist_show(struct hostapd_data *hapd, char *buf, + size_t buflen); +int hostapd_ctrl_iface_blacklist_clr(struct hostapd_data *hapd); #endif /* CTRL_IFACE_AP_H */ diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c index 30f57f4..6bb3897 100644 --- a/src/ap/hostapd.c +++ b/src/ap/hostapd.c @@ -1839,6 +1839,7 @@ dfs_offload: for (j = 0; j < iface->num_bss; j++) hostapd_set_own_neighbor_report(iface->bss[j]); + hapd->blacklist = NULL; return 0; fail: diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h index 195679e..ab7635c 100644 --- a/src/ap/hostapd.h +++ b/src/ap/hostapd.h @@ -19,6 +19,7 @@ struct radius_server_data; struct upnp_wps_device_sm; struct hostapd_data; struct sta_info; +struct sta_blacklist; struct ieee80211_ht_capabilities; struct full_dynamic_vlan; enum wps_event; @@ -120,6 +121,8 @@ struct hostapd_data { struct hostapd_bss_config *conf; int interface_added; /* virtual interface added for this BSS */ unsigned int started:1; + /* Client station blacklist support */ + struct sta_blacklist *blacklist; unsigned int disabled:1; unsigned int reenable_beacon:1; diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c index 11f12f9..70d6005 100644 --- a/src/ap/ieee802_11.c +++ b/src/ap/ieee802_11.c @@ -28,6 +28,7 @@ #include "beacon.h" #include "ieee802_11_auth.h" #include "sta_info.h" +#include "sta_blacklist.h" #include "ieee802_1x.h" #include "wpa_auth.h" #include "pmksa_cache_auth.h" @@ -944,7 +945,6 @@ remove_sta: wpabuf_free(data); } - /** * auth_sae_init_committed - Send COMMIT and start SAE in committed state * @hapd: BSS data for the device initiating the authentication @@ -1045,6 +1045,16 @@ static void handle_auth(struct hostapd_data *hapd, } #endif /* CONFIG_NO_RC4 */ + // Check for existence in blacklist + if(sta_blacklist_present(hapd, mgmt->sa)) { + hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211, + HOSTAPD_LEVEL_INFO, "auth failed from " MACSTR " due to blacklist", MAC2STR(mgmt->sa)); + + resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA; + goto fail; + } + + if (hapd->tkip_countermeasures) { resp = WLAN_REASON_MICHAEL_MIC_FAILURE; goto fail; diff --git a/src/ap/sta_blacklist.c b/src/ap/sta_blacklist.c new file mode 100644 index 0000000..40838cd --- /dev/null +++ b/src/ap/sta_blacklist.c @@ -0,0 +1,140 @@ +#include "utils/includes.h" + +#include "utils/common.h" +#include "common/ieee802_11_defs.h" +#include "eapol_auth/eapol_auth_sm.h" +#include "hostapd.h" +#include "ieee802_1x.h" +#include "wpa_auth.h" +#include "ieee802_11.h" +#include "sta_info.h" +#include "sta_blacklist.h" + +/** + * sta_blacklist_get - Get the blacklist entry for a BSSID + * @wpa_s: Pointer to wpa_supplicant data + * @bssid: BSSID + * Returns: Matching blacklist entry for the BSSID or %NULL if not found + */ +struct sta_blacklist * sta_blacklist_get(struct hostapd_data *hapd, const u8 *sta) { + struct sta_blacklist *e; + + if (hapd == NULL || sta == NULL) + return NULL; + + e = hapd->blacklist; + while (e) { + if (os_memcmp(e->sta, sta, ETH_ALEN) == 0) + return e; + e = e->next; + } + + return NULL; +} + +int sta_blacklist_present(struct hostapd_data *hapd, const u8 *sta) +{ + if(sta_blacklist_get(hapd, sta) != NULL) + return 1; + + return 0; +} + + + +/** + * wpa_blacklist_add - Add an BSSID to the blacklist + * @wpa_s: Pointer to wpa_supplicant data + * @bssid: BSSID to be added to the blacklist + * Returns: Current blacklist count on success, -1 on failure + * + * This function adds the specified BSSID to the blacklist or increases the + * blacklist count if the BSSID was already listed. It should be called when + * an association attempt fails either due to the selected BSS rejecting + * association or due to timeout. + * + * This blacklist is used to force %wpa_supplicant to go through all available + * BSSes before retrying to associate with an BSS that rejected or timed out + * association. It does not prevent the listed BSS from being used; it only + * changes the order in which they are tried. + */ +int sta_blacklist_add(struct hostapd_data *hapd, const u8 *sta) { + struct sta_blacklist *e; + + if (hapd == NULL || sta == NULL) + return -1; + + e = sta_blacklist_get(hapd, sta); + if (e) { + return 0; + } + + e = os_zalloc(sizeof(*e)); + if (e == NULL) + return -1; + os_memcpy(e->sta, sta, ETH_ALEN); + + + e->next = hapd->blacklist; + hapd->blacklist = e; + + hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211, + HOSTAPD_LEVEL_INFO, "Added BSSID " MACSTR " into blacklist", MAC2STR(sta)); + + return 0; +} + +/** + * wpa_blacklist_del - Remove an BSSID from the blacklist + * @wpa_s: Pointer to wpa_supplicant data + * @bssid: BSSID to be removed from the blacklist + * Returns: 0 on success, -1 on failure + */ +int sta_blacklist_rm(struct hostapd_data *hapd, const u8 *sta) { + struct sta_blacklist *e, *prev = NULL; + + if (hapd == NULL || sta == NULL) + return -1; + + e = hapd->blacklist; + while (e) { + if (os_memcmp(e->sta, sta, ETH_ALEN) == 0) { + if (prev == NULL) { + hapd->blacklist = e->next; + } else { + prev->next = e->next; + } + + hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211, + HOSTAPD_LEVEL_INFO, "Removed BSSID " MACSTR " from blacklist", MAC2STR(sta)); + + os_free(e); + + return 0; + } + prev = e; + e = e->next; + } + return -1; +} + +/** + * wpa_blacklist_clear - Clear the blacklist of all entries + * @wpa_s: Pointer to wpa_supplicant data + */ +int sta_blacklist_clear(struct hostapd_data *hapd) { + struct sta_blacklist *e, *prev; + + e = hapd->blacklist; + hapd->blacklist = NULL; + while (e) { + prev = e; + e = e->next; + hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211, + HOSTAPD_LEVEL_INFO, "Removed BSSID " MACSTR " from blacklist", MAC2STR(prev->sta)); + //wpa_printf(MSG_ERROR, "Removed BSSID " MACSTR " from blacklist (clear)", MAC2STR(prev->sta)); + os_free(prev); + } + + return 0; +} diff --git a/src/ap/sta_blacklist.h b/src/ap/sta_blacklist.h new file mode 100644 index 0000000..243a277 --- /dev/null +++ b/src/ap/sta_blacklist.h @@ -0,0 +1,14 @@ +#ifndef STA_BLACKLIST_H +#define STA_BLACKLIST_H + +struct sta_blacklist { + struct sta_blacklist *next; + u8 sta[ETH_ALEN]; +}; + +struct sta_blacklist * sta_blacklist_get(struct hostapd_data *hapd, const u8 *sta); +int sta_blacklist_present(struct hostapd_data *hapd, const u8 *sta); +int sta_blacklist_add(struct hostapd_data *hapd, const u8 *sta); +int sta_blacklist_rm(struct hostapd_data *hapd, const u8 *sta); +int sta_blacklist_clear(struct hostapd_data *hapd); +#endif /* STA_BLACKLIST_H */ -- 1.9.1
_______________________________________________ Hostap mailing list Hostap@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/hostap