From 5e590ea1196c8bc0e4869753e2eba72be36ae320 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= Date: Tue, 3 Jul 2018 23:27:00 +0200 Subject: [PATCH] [Web] Allow to blacklist, whitelist and unban networks currently blocked plus minor other fixes to fail2ban logic --- data/web/admin.php | 30 +++++++++++- data/web/inc/functions.fail2ban.inc.php | 65 +++++++++++++++++++++---- data/web/json_api.php | 2 +- data/web/lang/lang.de.php | 4 ++ data/web/lang/lang.en.php | 4 ++ 5 files changed, 93 insertions(+), 12 deletions(-) diff --git a/data/web/admin.php b/data/web/admin.php index 980f663b..8bd07000 100644 --- a/data/web/admin.php +++ b/data/web/admin.php @@ -416,8 +416,36 @@ $tfa_data = get_tfa(); - + +
+

+ + + +

() - + + [] + [whitelist] + [blacklist] + + + +

+ diff --git a/data/web/inc/functions.fail2ban.inc.php b/data/web/inc/functions.fail2ban.inc.php index 75f78e72..24d672bb 100644 --- a/data/web/inc/functions.fail2ban.inc.php +++ b/data/web/inc/functions.fail2ban.inc.php @@ -1,4 +1,14 @@ = 0 && $cidr[1] <= 32))) { + return true; + } + elseif (filter_var($cidr[0], FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) && (!isset($cidr[1]) || ($cidr[1] >= 0 && $cidr[1] <= 128))) { + return true; + } + return false; +} function fail2ban($_action, $_data = null) { global $redis; global $lang; @@ -42,6 +52,22 @@ function fail2ban($_action, $_data = null) { else { $f2b_options['blacklist'] = ""; } + $active_bans = $redis->hGetAll('F2B_ACTIVE_BANS'); + $queue_unban = $redis->hGetAll('F2B_QUEUE_UNBAN'); + if (is_array($active_bans)) { + foreach ($active_bans as $network => $banned_until) { + $queued_for_unban = (isset($queue_unban[$network]) && $queue_unban[$network] == 1) ? 1 : 0; + $difference = $banned_until - time(); + $f2b_options['active_bans'][] = array( + 'queued_for_unban' => $queued_for_unban, + 'network' => $network, + 'banned_until' => sprintf('%02dh %02dm %02ds', ($difference/3600), ($difference/60%60), $difference%60) + ); + } + } + else { + $f2b_options['active_bans'] = ""; + } } catch (RedisException $e) { $_SESSION['return'] = array( @@ -60,6 +86,33 @@ function fail2ban($_action, $_data = null) { ); return false; } + if (isset($_data['action']) && !empty($_data['network'])) { + $networks = (array) $_data['network']; + foreach ($networks as $network) { + if ($_data['action'] == "unban") { + if (valid_network($network)) { + $redis->hSet('F2B_QUEUE_UNBAN', $network, 1); + } + } + elseif ($_data['action'] == "whitelist") { + if (valid_network($network)) { + $redis->hSet('F2B_WHITELIST', $network, 1); + $redis->hDel('F2B_BLACKLIST', $network, 1); + $redis->hSet('F2B_QUEUE_UNBAN', $network, 1); + } + } + elseif ($_data['action'] == "blacklist") { + if (valid_network($network)) { + $redis->hSet('F2B_BLACKLIST', $network, 1); + } + } + } + $_SESSION['return'] = array( + 'type' => 'success', + 'msg' => sprintf($lang['success']['object_modified'], htmlspecialchars(implode(', ', $networks))) + ); + return true; + } $is_now = fail2ban('get'); if (!empty($is_now)) { $ban_time = intval((isset($_data['ban_time'])) ? $_data['ban_time'] : $is_now['ban_time']); @@ -93,11 +146,7 @@ function fail2ban($_action, $_data = null) { $wl_array = array_map('trim', preg_split( "/( |,|;|\n)/", $wl)); if (is_array($wl_array)) { foreach ($wl_array as $wl_item) { - $cidr = explode('/', $wl_item); - if (filter_var($cidr[0], FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) && (!isset($cidr[1]) || ($cidr[1] >= 0 && $cidr[1] <= 32))) { - $redis->hSet('F2B_WHITELIST', $wl_item, 1); - } - elseif (filter_var($cidr[0], FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) && (!isset($cidr[1]) || ($cidr[1] >= 0 && $cidr[1] <= 128))) { + if (valid_network($wl_item)) { $redis->hSet('F2B_WHITELIST', $wl_item, 1); } } @@ -107,11 +156,7 @@ function fail2ban($_action, $_data = null) { $bl_array = array_map('trim', preg_split( "/( |,|;|\n)/", $bl)); if (is_array($bl_array)) { foreach ($bl_array as $bl_item) { - $cidr = explode('/', $bl_item); - if (filter_var($cidr[0], FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) && (!isset($cidr[1]) || ($cidr[1] >= 0 && $cidr[1] <= 32))) { - $redis->hSet('F2B_BLACKLIST', $bl_item, 1); - } - elseif (filter_var($cidr[0], FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) && (!isset($cidr[1]) || ($cidr[1] >= 0 && $cidr[1] <= 128))) { + if (valid_network($bl_item)) { $redis->hSet('F2B_BLACKLIST', $bl_item, 1); } } diff --git a/data/web/json_api.php b/data/web/json_api.php index 7faa8841..459bd983 100644 --- a/data/web/json_api.php +++ b/data/web/json_api.php @@ -1119,7 +1119,7 @@ if (isset($_SESSION['mailcow_cc_role']) || isset($_SESSION['pending_mailcow_cc_u process_edit_return(fwdhost('edit', array_merge(array('fwdhost' => $items), $attr))); break; case "fail2ban": - process_edit_return(fail2ban('edit', $attr)); + process_edit_return(fail2ban('edit', array_merge(array('network' => $items), $attr))); break; case "ui_texts": process_edit_return(customize('edit', 'ui_texts', $attr)); diff --git a/data/web/lang/lang.de.php b/data/web/lang/lang.de.php index 6e92806f..1ebd9da0 100644 --- a/data/web/lang/lang.de.php +++ b/data/web/lang/lang.de.php @@ -450,6 +450,10 @@ $lang['admin']['api_allow_from'] = "IP-Adressen für Zugriff"; $lang['admin']['api_key'] = "API-Key"; $lang['admin']['activate_api'] = "API aktivieren"; $lang['admin']['regen_api_key'] = "API-Key regenerieren"; +$lang['admin']['ban_list_info'] = "Übersicht ausgesperrter Netzwerke: Netzwerk (verbleibende Banzeit) - [Aktionen].
IPs, die zum Unban eingereiht werden, verlassen die Liste aktiver Bans nach wenigen Sekunden."; +$lang['admin']['unban_pending'] = "ausstehend"; +$lang['admin']['queue_unban'] = "Unban einreihen"; +$lang['admin']['no_active_bans'] = "Keine aktiven Bans"; $lang['admin']['quarantine'] = "Quarantäne"; $lang['admin']['quarantine_retention_size'] = "Rückhaltungen pro Mailbox
0 bedeutet inaktiv!"; diff --git a/data/web/lang/lang.en.php b/data/web/lang/lang.en.php index bdc25143..d5602beb 100644 --- a/data/web/lang/lang.en.php +++ b/data/web/lang/lang.en.php @@ -471,6 +471,10 @@ $lang['admin']['api_allow_from'] = "Allow API access from these IPs"; $lang['admin']['api_key'] = "API key"; $lang['admin']['activate_api'] = "Activate API"; $lang['admin']['regen_api_key'] = "Regenerate API key"; +$lang['admin']['ban_list_info'] = "See a list of banned IPs below: network (remaining ban time) - [actions].
IPs queued to be unbanned, will be removed from the active ban list within a few seconds."; +$lang['admin']['unban_pending'] = "unban pending"; +$lang['admin']['queue_unban'] = "queue unban"; +$lang['admin']['no_active_bans'] = "No active bans"; $lang['admin']['quarantine'] = "Quarantine"; $lang['admin']['quarantine_retention_size'] = "Retentions per mailbox
0 indicates inactive!";