From ed6f5ea55a2f6116e985d397d64e5eee46c90728 Mon Sep 17 00:00:00 2001 From: James Prestwood Date: Thu, 24 Jan 2019 15:29:13 -0800 Subject: [PATCH] blacklist: add blacklist.[ch] to build and main This will allow for blacklisting a BSS if the connection fails. The actual blacklist module is simple and must be driven by station. All it does is add BSS addresses, a timestamp, and a timeout to a queue. Entries can also be removed, or checked if they exist. The blacklist timeout is configuratble in main.conf, as well as the blacklist timeout multiplier and maximum timeout. The multiplier is used after a blacklisted BSS timeout expires but we still fail to connect on the next connection attempt. We multiply the current timeout by the multiplier so the BSS remains in the blacklist for a larger growing amount of time until it reaches the maximum (24 hours by default). --- Makefile.am | 1 + src/blacklist.c | 183 ++++++++++++++++++++++++++++++++++++++++++++++++ src/blacklist.h | 28 ++++++++ src/main.c | 3 + 4 files changed, 215 insertions(+) create mode 100644 src/blacklist.c create mode 100644 src/blacklist.h diff --git a/Makefile.am b/Makefile.am index 58d93dd1..157a1087 100644 --- a/Makefile.am +++ b/Makefile.am @@ -200,6 +200,7 @@ src_iwd_SOURCES = src/main.c linux/nl80211.h src/iwd.h \ src/sae.h src/sae.c \ src/nl80211util.h src/nl80211util.c \ src/owe.h src/owe.c \ + src/blacklist.h src/blacklist.c \ $(eap_sources) \ $(builtin_sources) src_iwd_LDADD = $(ell_ldadd) -ldl diff --git a/src/blacklist.c b/src/blacklist.c new file mode 100644 index 00000000..2da276f7 --- /dev/null +++ b/src/blacklist.c @@ -0,0 +1,183 @@ +/* + * + * Wireless daemon for Linux + * + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include "src/blacklist.h" +#include "src/util.h" +#include "src/iwd.h" + +/* + * The current timeout is multiplied by this value after an entry is blacklisted + * more than once. + */ +#define BLACKLIST_DEFAULT_MULTIPLIER 30 + +/* Initial timeout for a new blacklist entry */ +#define BLACKLIST_DEFAULT_TIMEOUT 60 + +/* The maximum amount of time a BSS can be blacklisted for */ +#define BLACKLIST_DEFAULT_MAX_TIMEOUT 86400 + +static uint64_t blacklist_multiplier; +static uint64_t blacklist_initial_timeout; +static uint64_t blacklist_max_timeout; + +struct blacklist_entry { + uint8_t addr[6]; + uint64_t added_time; + uint64_t expire_time; +}; + +static struct l_queue *blacklist; + +static bool check_if_expired(void *data, void *user_data) +{ + struct blacklist_entry *entry = data; + uint64_t now = l_get_u64(user_data); + + if (l_time_diff(now, entry->added_time) > blacklist_max_timeout) { + l_debug("Removing entry "MAC" on prune", MAC_STR(entry->addr)); + l_free(entry); + return true; + } + + return false; +} + +static void blacklist_prune(void) +{ + uint64_t now = l_time_now(); + + l_queue_foreach_remove(blacklist, check_if_expired, &now); +} + +static bool match_addr(const void *a, const void *b) +{ + const struct blacklist_entry *entry = a; + const uint8_t *addr = b; + + if (!memcmp(entry->addr, addr, 6)) + return true; + + return false; +} + +void blacklist_add_bss(const uint8_t *addr) +{ + struct blacklist_entry *entry; + + blacklist_prune(); + + entry = l_queue_find(blacklist, match_addr, addr); + + if (entry) { + uint64_t offset = l_time_diff(entry->added_time, + entry->expire_time); + + offset *= blacklist_multiplier; + + if (offset > blacklist_max_timeout) + offset = blacklist_max_timeout; + + entry->expire_time = l_time_offset(entry->added_time, offset); + + return; + } + + entry = l_new(struct blacklist_entry, 1); + + entry->added_time = l_time_now(); + entry->expire_time = l_time_offset(entry->added_time, + blacklist_initial_timeout); + memcpy(entry->addr, addr, 6); + + l_queue_push_tail(blacklist, entry); +} + +bool blacklist_contains_bss(const uint8_t *addr) +{ + bool ret; + uint64_t time_now; + struct blacklist_entry *entry; + + blacklist_prune(); + + entry = l_queue_find(blacklist, match_addr, addr); + + if (!entry) + return false; + + time_now = l_time_now(); + + ret = l_time_after(time_now, entry->expire_time) ? false : true; + + return ret; +} + +void blacklist_remove_bss(const uint8_t *addr) +{ + struct blacklist_entry *entry; + + blacklist_prune(); + + entry = l_queue_remove_if(blacklist, match_addr, addr); + + if (!entry) + return; + + l_free(entry); +} + +void blacklist_init(void) +{ + const struct l_settings *config = iwd_get_config(); + + if (!l_settings_get_uint64(config, "Blacklist", "bss_blacklist_time", + &blacklist_initial_timeout)) + blacklist_initial_timeout = BLACKLIST_DEFAULT_TIMEOUT; + + /* For easier user configuration the timeout values are in seconds */ + blacklist_initial_timeout *= 1000000; + + if (!l_settings_get_uint64(config, "Blacklist", + "bss_blacklist_multiplier", + &blacklist_multiplier)) + blacklist_multiplier = BLACKLIST_DEFAULT_MULTIPLIER; + + if (!l_settings_get_uint64(config, "Blacklist", "bss_blacklist_max_time", + &blacklist_max_timeout)) + blacklist_max_timeout = BLACKLIST_DEFAULT_MAX_TIMEOUT; + + blacklist_max_timeout *= 1000000; + + blacklist = l_queue_new(); +} + +void blacklist_exit(void) +{ + l_queue_destroy(blacklist, l_free); +} diff --git a/src/blacklist.h b/src/blacklist.h new file mode 100644 index 00000000..8161f4ed --- /dev/null +++ b/src/blacklist.h @@ -0,0 +1,28 @@ +/* + * + * Wireless daemon for Linux + * + * Copyright (C) 2019 Intel Corporation. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +void blacklist_add_bss(const uint8_t *addr); +bool blacklist_contains_bss(const uint8_t *addr); +void blacklist_remove_bss(const uint8_t *addr); + +void blacklist_init(void); +void blacklist_exit(void); diff --git a/src/main.c b/src/main.c index e0ccbef2..e9f91134 100644 --- a/src/main.c +++ b/src/main.c @@ -44,6 +44,7 @@ #include "src/plugin.h" #include "src/simauth.h" #include "src/adhoc.h" +#include "src/blacklist.h" #include "src/backtrace.h" @@ -498,9 +499,11 @@ int main(int argc, char *argv[]) known_networks_init(); sim_auth_init(); plugin_init(plugins, noplugins); + blacklist_init(); exit_status = l_main_run_with_signal(signal_handler, NULL); + blacklist_exit(); plugin_exit(); sim_auth_exit(); known_networks_exit();