From e2e8fbe3131327eb65f22e31fb200d55c59512dd Mon Sep 17 00:00:00 2001 From: FreddleSpl0it Date: Mon, 10 Jul 2023 13:54:23 +0200 Subject: [PATCH 1/6] [Web] add f2b_banlist endpoint --- data/Dockerfiles/netfilter/server.py | 2 + data/web/admin.php | 6 +- data/web/inc/functions.fail2ban.inc.php | 65 +++++++++++++++++++- data/web/inc/functions.inc.php | 15 +++++ data/web/js/build/013-mailcow.js | 8 +++ data/web/json_api.php | 21 ++++++- data/web/lang/lang.de-de.json | 2 + data/web/lang/lang.en-gb.json | 2 + data/web/templates/admin/tab-config-f2b.twig | 9 +++ 9 files changed, 127 insertions(+), 3 deletions(-) diff --git a/data/Dockerfiles/netfilter/server.py b/data/Dockerfiles/netfilter/server.py index 698137bf..9f3cacb3 100644 --- a/data/Dockerfiles/netfilter/server.py +++ b/data/Dockerfiles/netfilter/server.py @@ -16,6 +16,7 @@ import json import iptc import dns.resolver import dns.exception +import uuid while True: try: @@ -94,6 +95,7 @@ def verifyF2boptions(f2boptions): verifyF2boption(f2boptions,'retry_window', 600) verifyF2boption(f2boptions,'netban_ipv4', 32) verifyF2boption(f2boptions,'netban_ipv6', 128) + verifyF2boption(f2boptions,'banlist_id', str(uuid.uuid4())) def verifyF2boption(f2boptions, f2boption, f2bdefault): f2boptions[f2boption] = f2boptions[f2boption] if f2boption in f2boptions and f2boptions[f2boption] is not None else f2bdefault diff --git a/data/web/admin.php b/data/web/admin.php index 14cb89f5..8a96ee51 100644 --- a/data/web/admin.php +++ b/data/web/admin.php @@ -85,6 +85,8 @@ $cors_settings = cors('get'); $cors_settings['allowed_origins'] = str_replace(", ", "\n", $cors_settings['allowed_origins']); $cors_settings['allowed_methods'] = explode(", ", $cors_settings['allowed_methods']); +$f2b_data = fail2ban('get'); + $template = 'admin.twig'; $template_data = [ 'tfa_data' => $tfa_data, @@ -101,7 +103,8 @@ $template_data = [ 'domains' => $domains, 'all_domains' => $all_domains, 'mailboxes' => $mailboxes, - 'f2b_data' => fail2ban('get'), + 'f2b_data' => $f2b_data, + 'f2b_banlist_url' => getBaseUrl() . "/api/v1/get/fail2ban/banlist/" . $f2b_data['banlist_id'], 'q_data' => quarantine('settings'), 'qn_data' => quota_notification('get'), 'rsettings_map' => file_get_contents('http://nginx:8081/settings.php'), @@ -112,6 +115,7 @@ $template_data = [ 'password_complexity' => password_complexity('get'), 'show_rspamd_global_filters' => @$_SESSION['show_rspamd_global_filters'], 'cors_settings' => $cors_settings, + 'is_https' => isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on', 'lang_admin' => json_encode($lang['admin']), 'lang_datatables' => json_encode($lang['datatables']) ]; diff --git a/data/web/inc/functions.fail2ban.inc.php b/data/web/inc/functions.fail2ban.inc.php index 2c4aa41d..3e0c75c4 100644 --- a/data/web/inc/functions.fail2ban.inc.php +++ b/data/web/inc/functions.fail2ban.inc.php @@ -1,5 +1,5 @@ 'f2b_modified' ); break; + case 'banlist': + try { + $f2b_options = json_decode($redis->Get('F2B_OPTIONS'), true); + } + catch (RedisException $e) { + $_SESSION['return'][] = array( + 'type' => 'danger', + 'log' => array(__FUNCTION__, $_action, $_data_log, $_extra), + 'msg' => array('redis_error', $e) + ); + return false; + } + if (is_array($_extra)) { + $_extra = $_extra[0]; + } + if ($_extra != $f2b_options['banlist_id']){ + return false; + } + + switch ($_data) { + case 'get': + try { + $bl = $redis->hGetAll('F2B_BLACKLIST'); + $active_bans = $redis->hGetAll('F2B_ACTIVE_BANS'); + } + catch (RedisException $e) { + $_SESSION['return'][] = array( + 'type' => 'danger', + 'log' => array(__FUNCTION__, $_action, $_data_log, $_extra), + 'msg' => array('redis_error', $e) + ); + return false; + } + $banlist = implode("\n", array_merge(array_keys($bl), array_keys($active_bans))); + return $banlist; + break; + case 'refresh': + if ($_SESSION['mailcow_cc_role'] != "admin") { + return false; + } + + $f2b_options['banlist_id'] = uuid4(); + try { + $redis->Set('F2B_OPTIONS', json_encode($f2b_options)); + } + catch (RedisException $e) { + $_SESSION['return'][] = array( + 'type' => 'danger', + 'log' => array(__FUNCTION__, $_action, $_data_log, $_extra), + 'msg' => array('redis_error', $e) + ); + return false; + } + + $_SESSION['return'][] = array( + 'type' => 'success', + 'log' => array(__FUNCTION__, $_action, $_data_log, $_extra), + 'msg' => 'f2b_banlist_refreshed' + ); + return true; + break; + } + break; } } diff --git a/data/web/inc/functions.inc.php b/data/web/inc/functions.inc.php index 6418945c..3cff09b9 100644 --- a/data/web/inc/functions.inc.php +++ b/data/web/inc/functions.inc.php @@ -2246,6 +2246,21 @@ function cors($action, $data = null) { break; } } +function getBaseURL() { + $protocol = isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? 'https' : 'http'; + $host = $_SERVER['HTTP_HOST']; + $base_url = $protocol . '://' . $host; + + return $base_url; +} +function uuid4() { + $data = openssl_random_pseudo_bytes(16); + + $data[6] = chr(ord($data[6]) & 0x0f | 0x40); + $data[8] = chr(ord($data[8]) & 0x3f | 0x80); + + return vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($data), 4)); +} function get_logs($application, $lines = false) { if ($lines === false) { diff --git a/data/web/js/build/013-mailcow.js b/data/web/js/build/013-mailcow.js index e659915b..cc54fafb 100644 --- a/data/web/js/build/013-mailcow.js +++ b/data/web/js/build/013-mailcow.js @@ -371,3 +371,11 @@ function addTag(tagAddElem, tag = null){ $(tagValuesElem).val(JSON.stringify(value_tags)); $(tagInputElem).val(''); } +function copyToClipboard(id) { + var copyText = document.getElementById(id); + copyText.select(); + copyText.setSelectionRange(0, 99999); + // only works with https connections + navigator.clipboard.writeText(copyText.value); + mailcow_alert_box(lang.copy_to_clipboard, "success"); +} \ No newline at end of file diff --git a/data/web/json_api.php b/data/web/json_api.php index 16c78baf..50a45b56 100644 --- a/data/web/json_api.php +++ b/data/web/json_api.php @@ -503,6 +503,15 @@ if (isset($_GET['query'])) { print(json_encode($getArgs)); $_SESSION['challenge'] = $WebAuthn->getChallenge(); return; + break; + case "fail2ban": + if (!isset($_SESSION['mailcow_cc_role'])){ + switch ($object) { + case 'banlist': + echo fail2ban('banlist', 'get', $extra); + break; + } + } break; } if (isset($_SESSION['mailcow_cc_role'])) { @@ -1324,6 +1333,9 @@ if (isset($_GET['query'])) { break; case "fail2ban": switch ($object) { + case 'banlist': + echo fail2ban('banlist', 'get', $extra); + break; default: $data = fail2ban('get'); process_get_return($data); @@ -1930,7 +1942,14 @@ if (isset($_GET['query'])) { process_edit_return(fwdhost('edit', array_merge(array('fwdhost' => $items), $attr))); break; case "fail2ban": - process_edit_return(fail2ban('edit', array_merge(array('network' => $items), $attr))); + switch ($object) { + case 'banlist': + process_edit_return(fail2ban('banlist', 'refresh', $items)); + break; + default: + process_edit_return(fail2ban('edit', array_merge(array('network' => $items), $attr))); + break; + } break; case "ui_texts": process_edit_return(customize('edit', 'ui_texts', $attr)); diff --git a/data/web/lang/lang.de-de.json b/data/web/lang/lang.de-de.json index d6f79dc5..2091e670 100644 --- a/data/web/lang/lang.de-de.json +++ b/data/web/lang/lang.de-de.json @@ -147,6 +147,7 @@ "change_logo": "Logo ändern", "configuration": "Konfiguration", "convert_html_to_text": "Konvertiere HTML zu reinem Text", + "copy_to_clipboard": "Text wurde in die Zwischenablage kopiert!", "cors_settings": "CORS Einstellungen", "credentials_transport_warning": "Warnung: Das Hinzufügen einer neuen Regel bewirkt die Aktualisierung der Authentifizierungsdaten aller vorhandenen Einträge mit identischem Next Hop.", "customer_id": "Kunde", @@ -1019,6 +1020,7 @@ "domain_removed": "Domain %s wurde entfernt", "dovecot_restart_success": "Dovecot wurde erfolgreich neu gestartet", "eas_reset": "ActiveSync Gerät des Benutzers %s wurde zurückgesetzt", + "f2b_banlist_refreshed": "Banlist ID wurde erfolgreich erneuert.", "f2b_modified": "Änderungen an Fail2ban-Parametern wurden gespeichert", "forwarding_host_added": "Weiterleitungs-Host %s wurde hinzugefügt", "forwarding_host_removed": "Weiterleitungs-Host %s wurde entfernt", diff --git a/data/web/lang/lang.en-gb.json b/data/web/lang/lang.en-gb.json index 28ff19b8..b176bc28 100644 --- a/data/web/lang/lang.en-gb.json +++ b/data/web/lang/lang.en-gb.json @@ -151,6 +151,7 @@ "change_logo": "Change logo", "configuration": "Configuration", "convert_html_to_text": "Convert HTML to plain text", + "copy_to_clipboard": "Text copied to clipboard!", "cors_settings": "CORS Settings", "credentials_transport_warning": "Warning: Adding a new transport map entry will update the credentials for all entries with a matching next hop column.", "customer_id": "Customer ID", @@ -1028,6 +1029,7 @@ "domain_removed": "Domain %s has been removed", "dovecot_restart_success": "Dovecot was restarted successfully", "eas_reset": "ActiveSync devices for user %s were reset", + "f2b_banlist_refreshed": "Banlist ID has been successfully refreshed.", "f2b_modified": "Changes to Fail2ban parameters have been saved", "forwarding_host_added": "Forwarding host %s has been added", "forwarding_host_removed": "Forwarding host %s has been removed", diff --git a/data/web/templates/admin/tab-config-f2b.twig b/data/web/templates/admin/tab-config-f2b.twig index c15fb72f..68aa57a4 100644 --- a/data/web/templates/admin/tab-config-f2b.twig +++ b/data/web/templates/admin/tab-config-f2b.twig @@ -90,6 +90,15 @@ {% if not f2b_data.active_bans and not f2b_data.perm_bans %} {{ lang.admin.no_active_bans }} {% endif %} +
+
+ + {% if is_https %} + + {% endif %} + +
+
{% for active_ban in f2b_data.active_bans %}

From 65cbc478b8ac644c826bbb5153bd557f29cda10f Mon Sep 17 00:00:00 2001 From: FreddleSpl0it Date: Tue, 11 Jul 2023 10:13:00 +0200 Subject: [PATCH 2/6] [Web] add manage f2b external option --- data/Dockerfiles/netfilter/server.py | 79 ++++++++++++-------- data/web/inc/functions.fail2ban.inc.php | 9 ++- data/web/lang/lang.de-de.json | 2 + data/web/lang/lang.en-gb.json | 2 + data/web/templates/admin/tab-config-f2b.twig | 7 ++ 5 files changed, 65 insertions(+), 34 deletions(-) diff --git a/data/Dockerfiles/netfilter/server.py b/data/Dockerfiles/netfilter/server.py index 9f3cacb3..428ddb96 100644 --- a/data/Dockerfiles/netfilter/server.py +++ b/data/Dockerfiles/netfilter/server.py @@ -96,6 +96,7 @@ def verifyF2boptions(f2boptions): verifyF2boption(f2boptions,'netban_ipv4', 32) verifyF2boption(f2boptions,'netban_ipv6', 128) verifyF2boption(f2boptions,'banlist_id', str(uuid.uuid4())) + verifyF2boption(f2boptions,'manage_external', 0) def verifyF2boption(f2boptions, f2boption, f2bdefault): f2boptions[f2boption] = f2boptions[f2boption] if f2boption in f2boptions and f2boptions[f2boption] is not None else f2bdefault @@ -158,6 +159,7 @@ def mailcowChainOrder(): exit_code = 2 def ban(address): + global f2boptions global lock refreshF2boptions() BAN_TIME = int(f2boptions['ban_time']) @@ -199,7 +201,7 @@ def ban(address): cur_time = int(round(time.time())) NET_BAN_TIME = BAN_TIME if not BAN_TIME_INCREMENT else BAN_TIME * 2 ** bans[net]['ban_counter'] logCrit('Banning %s for %d minutes' % (net, NET_BAN_TIME / 60 )) - if type(ip) is ipaddress.IPv4Address: + if type(ip) is ipaddress.IPv4Address and int(f2boptions['manage_external']) != 1: with lock: chain = iptc.Chain(iptc.Table(iptc.Table.FILTER), 'MAILCOW') rule = iptc.Rule() @@ -208,7 +210,7 @@ def ban(address): rule.target = target if rule not in chain.rules: chain.insert_rule(rule) - else: + elif int(f2boptions['manage_external']) != 1: with lock: chain = iptc.Chain(iptc.Table6(iptc.Table6.FILTER), 'MAILCOW') rule = iptc.Rule6() @@ -253,37 +255,52 @@ def unban(net): bans[net]['ban_counter'] += 1 def permBan(net, unban=False): + global f2boptions global lock if type(ipaddress.ip_network(net, strict=False)) is ipaddress.IPv4Network: - with lock: - chain = iptc.Chain(iptc.Table(iptc.Table.FILTER), 'MAILCOW') - rule = iptc.Rule() - rule.src = net - target = iptc.Target(rule, "REJECT") - rule.target = target - if rule not in chain.rules and not unban: - logCrit('Add host/network %s to blacklist' % net) - chain.insert_rule(rule) - r.hset('F2B_PERM_BANS', '%s' % net, int(round(time.time()))) - elif rule in chain.rules and unban: - logCrit('Remove host/network %s from blacklist' % net) - chain.delete_rule(rule) - r.hdel('F2B_PERM_BANS', '%s' % net) + if int(f2boptions['manage_external']) != 1: + with lock: + chain = iptc.Chain(iptc.Table(iptc.Table.FILTER), 'MAILCOW') + rule = iptc.Rule() + rule.src = net + target = iptc.Target(rule, "REJECT") + rule.target = target + if rule not in chain.rules and not unban: + logCrit('Add host/network %s to blacklist' % net) + chain.insert_rule(rule) + r.hset('F2B_PERM_BANS', '%s' % net, int(round(time.time()))) + elif rule in chain.rules and unban: + logCrit('Remove host/network %s from blacklist' % net) + chain.delete_rule(rule) + r.hdel('F2B_PERM_BANS', '%s' % net) + elif not unban: + logCrit('Add host/network %s to blacklist' % net) + r.hset('F2B_PERM_BANS', '%s' % net, int(round(time.time()))) + elif unban: + logCrit('Remove host/network %s from blacklist' % net) + r.hdel('F2B_PERM_BANS', '%s' % net) else: - with lock: - chain = iptc.Chain(iptc.Table6(iptc.Table6.FILTER), 'MAILCOW') - rule = iptc.Rule6() - rule.src = net - target = iptc.Target(rule, "REJECT") - rule.target = target - if rule not in chain.rules and not unban: - logCrit('Add host/network %s to blacklist' % net) - chain.insert_rule(rule) - r.hset('F2B_PERM_BANS', '%s' % net, int(round(time.time()))) - elif rule in chain.rules and unban: - logCrit('Remove host/network %s from blacklist' % net) - chain.delete_rule(rule) - r.hdel('F2B_PERM_BANS', '%s' % net) + if int(f2boptions['manage_external']) != 1: + with lock: + chain = iptc.Chain(iptc.Table6(iptc.Table6.FILTER), 'MAILCOW') + rule = iptc.Rule6() + rule.src = net + target = iptc.Target(rule, "REJECT") + rule.target = target + if rule not in chain.rules and not unban: + logCrit('Add host/network %s to blacklist' % net) + chain.insert_rule(rule) + r.hset('F2B_PERM_BANS', '%s' % net, int(round(time.time()))) + elif rule in chain.rules and unban: + logCrit('Remove host/network %s from blacklist' % net) + chain.delete_rule(rule) + r.hdel('F2B_PERM_BANS', '%s' % net) + elif not unban: + logCrit('Add host/network %s to blacklist' % net) + r.hset('F2B_PERM_BANS', '%s' % net, int(round(time.time()))) + elif unban: + logCrit('Remove host/network %s from blacklist' % net) + r.hdel('F2B_PERM_BANS', '%s' % net) def quit(signum, frame): global quit_now @@ -555,7 +572,7 @@ def initChain(): chain.insert_rule(rule) if __name__ == '__main__': - + refreshF2boptions() # In case a previous session was killed without cleanup clear() # Reinit MAILCOW chain diff --git a/data/web/inc/functions.fail2ban.inc.php b/data/web/inc/functions.fail2ban.inc.php index 3e0c75c4..abc12cc3 100644 --- a/data/web/inc/functions.fail2ban.inc.php +++ b/data/web/inc/functions.fail2ban.inc.php @@ -247,6 +247,7 @@ function fail2ban($_action, $_data = null, $_extra = null) { $netban_ipv6 = intval((isset($_data['netban_ipv6'])) ? $_data['netban_ipv6'] : $is_now['netban_ipv6']); $wl = (isset($_data['whitelist'])) ? $_data['whitelist'] : $is_now['whitelist']; $bl = (isset($_data['blacklist'])) ? $_data['blacklist'] : $is_now['blacklist']; + $manage_external = (isset($_data['manage_external'])) ? intval($_data['manage_external']) : 0; } else { $_SESSION['return'][] = array( @@ -266,6 +267,8 @@ function fail2ban($_action, $_data = null, $_extra = null) { $f2b_options['netban_ipv6'] = ($netban_ipv6 > 128) ? 128 : $netban_ipv6; $f2b_options['max_attempts'] = ($max_attempts < 1) ? 1 : $max_attempts; $f2b_options['retry_window'] = ($retry_window < 1) ? 1 : $retry_window; + $f2b_options['banlist_id'] = $is_now['banlist_id']; + $f2b_options['manage_external'] = ($manage_external > 0) ? 1 : 0; try { $redis->Set('F2B_OPTIONS', json_encode($f2b_options)); $redis->Del('F2B_WHITELIST'); @@ -351,8 +354,8 @@ function fail2ban($_action, $_data = null, $_extra = null) { switch ($_data) { case 'get': try { - $bl = $redis->hGetAll('F2B_BLACKLIST'); - $active_bans = $redis->hGetAll('F2B_ACTIVE_BANS'); + $bl = $redis->hKeys('F2B_BLACKLIST'); + $active_bans = $redis->hKeys('F2B_ACTIVE_BANS'); } catch (RedisException $e) { $_SESSION['return'][] = array( @@ -362,7 +365,7 @@ function fail2ban($_action, $_data = null, $_extra = null) { ); return false; } - $banlist = implode("\n", array_merge(array_keys($bl), array_keys($active_bans))); + $banlist = implode("\n", array_merge($bl, $active_bans)); return $banlist; break; case 'refresh': diff --git a/data/web/lang/lang.de-de.json b/data/web/lang/lang.de-de.json index 2091e670..7c2171aa 100644 --- a/data/web/lang/lang.de-de.json +++ b/data/web/lang/lang.de-de.json @@ -181,6 +181,8 @@ "f2b_blacklist": "Blacklist für Netzwerke und Hosts", "f2b_filter": "Regex-Filter", "f2b_list_info": "Ein Host oder Netzwerk auf der Blacklist wird immer eine Whitelist-Einheit überwiegen. Die Aktualisierung der Liste dauert einige Sekunden.", + "f2b_manage_external": "Fail2Ban extern verwalten", + "f2b_manage_external_info": "Fail2ban wird die Banlist weiterhin pflegen, jedoch werden keine aktiven Regeln zum blockieren gesetzt. Die unten generierte Banlist, kann verwendet werden, um den Datenverkehr extern zu blockieren.", "f2b_max_attempts": "Max. Versuche", "f2b_max_ban_time": "Maximale Bannzeit in Sekunden", "f2b_netban_ipv4": "Netzbereich für IPv4-Banns (8-32)", diff --git a/data/web/lang/lang.en-gb.json b/data/web/lang/lang.en-gb.json index b176bc28..e7c82cda 100644 --- a/data/web/lang/lang.en-gb.json +++ b/data/web/lang/lang.en-gb.json @@ -185,6 +185,8 @@ "f2b_blacklist": "Blacklisted networks/hosts", "f2b_filter": "Regex filters", "f2b_list_info": "A blacklisted host or network will always outweigh a whitelist entity. List updates will take a few seconds to be applied.", + "f2b_manage_external": "Manage Fail2Ban externally", + "f2b_manage_external_info": "Fail2ban will still maintain the banlist, but it will not actively set rules to block traffic. Use the generated banlist below to externally block the traffic.", "f2b_max_attempts": "Max. attempts", "f2b_max_ban_time": "Max. ban time (s)", "f2b_netban_ipv4": "IPv4 subnet size to apply ban on (8-32)", diff --git a/data/web/templates/admin/tab-config-f2b.twig b/data/web/templates/admin/tab-config-f2b.twig index 68aa57a4..dac69516 100644 --- a/data/web/templates/admin/tab-config-f2b.twig +++ b/data/web/templates/admin/tab-config-f2b.twig @@ -42,6 +42,13 @@ +

+
+ + +
+

{{ lang.admin.f2b_manage_external_info }}

+

{{ lang.admin.f2b_list_info|raw }}

From 1537fb39c0c8c996a05ae677b5fa7e20775b4851 Mon Sep 17 00:00:00 2001 From: FreddleSpl0it Date: Tue, 11 Jul 2023 10:19:32 +0200 Subject: [PATCH 3/6] [Web] add manage f2b external option --- data/Dockerfiles/netfilter/server.py | 70 +++++++++++----------------- 1 file changed, 28 insertions(+), 42 deletions(-) diff --git a/data/Dockerfiles/netfilter/server.py b/data/Dockerfiles/netfilter/server.py index 428ddb96..982fa97c 100644 --- a/data/Dockerfiles/netfilter/server.py +++ b/data/Dockerfiles/netfilter/server.py @@ -258,49 +258,35 @@ def permBan(net, unban=False): global f2boptions global lock if type(ipaddress.ip_network(net, strict=False)) is ipaddress.IPv4Network: - if int(f2boptions['manage_external']) != 1: - with lock: - chain = iptc.Chain(iptc.Table(iptc.Table.FILTER), 'MAILCOW') - rule = iptc.Rule() - rule.src = net - target = iptc.Target(rule, "REJECT") - rule.target = target - if rule not in chain.rules and not unban: - logCrit('Add host/network %s to blacklist' % net) - chain.insert_rule(rule) - r.hset('F2B_PERM_BANS', '%s' % net, int(round(time.time()))) - elif rule in chain.rules and unban: - logCrit('Remove host/network %s from blacklist' % net) - chain.delete_rule(rule) - r.hdel('F2B_PERM_BANS', '%s' % net) - elif not unban: - logCrit('Add host/network %s to blacklist' % net) - r.hset('F2B_PERM_BANS', '%s' % net, int(round(time.time()))) - elif unban: - logCrit('Remove host/network %s from blacklist' % net) - r.hdel('F2B_PERM_BANS', '%s' % net) + with lock: + chain = iptc.Chain(iptc.Table(iptc.Table.FILTER), 'MAILCOW') + rule = iptc.Rule() + rule.src = net + target = iptc.Target(rule, "REJECT") + rule.target = target + if rule not in chain.rules and not unban and int(f2boptions['manage_external']) != 1: + logCrit('Add host/network %s to blacklist' % net) + chain.insert_rule(rule) + r.hset('F2B_PERM_BANS', '%s' % net, int(round(time.time()))) + elif rule in chain.rules and unban: + logCrit('Remove host/network %s from blacklist' % net) + chain.delete_rule(rule) + r.hdel('F2B_PERM_BANS', '%s' % net) else: - if int(f2boptions['manage_external']) != 1: - with lock: - chain = iptc.Chain(iptc.Table6(iptc.Table6.FILTER), 'MAILCOW') - rule = iptc.Rule6() - rule.src = net - target = iptc.Target(rule, "REJECT") - rule.target = target - if rule not in chain.rules and not unban: - logCrit('Add host/network %s to blacklist' % net) - chain.insert_rule(rule) - r.hset('F2B_PERM_BANS', '%s' % net, int(round(time.time()))) - elif rule in chain.rules and unban: - logCrit('Remove host/network %s from blacklist' % net) - chain.delete_rule(rule) - r.hdel('F2B_PERM_BANS', '%s' % net) - elif not unban: - logCrit('Add host/network %s to blacklist' % net) - r.hset('F2B_PERM_BANS', '%s' % net, int(round(time.time()))) - elif unban: - logCrit('Remove host/network %s from blacklist' % net) - r.hdel('F2B_PERM_BANS', '%s' % net) + with lock: + chain = iptc.Chain(iptc.Table6(iptc.Table6.FILTER), 'MAILCOW') + rule = iptc.Rule6() + rule.src = net + target = iptc.Target(rule, "REJECT") + rule.target = target + if rule not in chain.rules and not unban and int(f2boptions['manage_external']) != 1: + logCrit('Add host/network %s to blacklist' % net) + chain.insert_rule(rule) + r.hset('F2B_PERM_BANS', '%s' % net, int(round(time.time()))) + elif rule in chain.rules and unban: + logCrit('Remove host/network %s from blacklist' % net) + chain.delete_rule(rule) + r.hdel('F2B_PERM_BANS', '%s' % net) def quit(signum, frame): global quit_now From 987cfd5dae4014b35c183ce4be0e1f8856950116 Mon Sep 17 00:00:00 2001 From: FreddleSpl0it Date: Tue, 11 Jul 2023 10:31:25 +0200 Subject: [PATCH 4/6] [Web] f2b banlist - add http status codes --- data/web/inc/functions.fail2ban.inc.php | 3 +++ data/web/inc/prerequisites.inc.php | 1 + 2 files changed, 4 insertions(+) diff --git a/data/web/inc/functions.fail2ban.inc.php b/data/web/inc/functions.fail2ban.inc.php index abc12cc3..5962237f 100644 --- a/data/web/inc/functions.fail2ban.inc.php +++ b/data/web/inc/functions.fail2ban.inc.php @@ -342,12 +342,14 @@ function fail2ban($_action, $_data = null, $_extra = null) { 'log' => array(__FUNCTION__, $_action, $_data_log, $_extra), 'msg' => array('redis_error', $e) ); + http_response_code(500); return false; } if (is_array($_extra)) { $_extra = $_extra[0]; } if ($_extra != $f2b_options['banlist_id']){ + http_response_code(404); return false; } @@ -363,6 +365,7 @@ function fail2ban($_action, $_data = null, $_extra = null) { 'log' => array(__FUNCTION__, $_action, $_data_log, $_extra), 'msg' => array('redis_error', $e) ); + http_response_code(500); return false; } $banlist = implode("\n", array_merge($bl, $active_bans)); diff --git a/data/web/inc/prerequisites.inc.php b/data/web/inc/prerequisites.inc.php index b3b1cc13..f7fd80b4 100644 --- a/data/web/inc/prerequisites.inc.php +++ b/data/web/inc/prerequisites.inc.php @@ -70,6 +70,7 @@ try { } } catch (Exception $e) { +http_response_code(500); ?>
Connection to Redis failed.

The following error was reported:
getMessage();?>
Date: Wed, 12 Jul 2023 09:42:17 +0200 Subject: [PATCH 5/6] [Netfilter] Update Compose File to 1.53 --- docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index 4c854aeb..b68a97fa 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -426,7 +426,7 @@ services: - acme netfilter-mailcow: - image: mailcow/netfilter:1.52 + image: mailcow/netfilter:1.53 stop_grace_period: 30s depends_on: - dovecot-mailcow From db2759b7d184e68713bf0441f84df9f624ce3c6d Mon Sep 17 00:00:00 2001 From: FreddleSpl0it Date: Wed, 12 Jul 2023 16:46:32 +0200 Subject: [PATCH 6/6] [Web] fix wrong content type + add more http 500 responses --- data/web/inc/prerequisites.inc.php | 3 +++ data/web/json_api.php | 2 ++ 2 files changed, 5 insertions(+) diff --git a/data/web/inc/prerequisites.inc.php b/data/web/inc/prerequisites.inc.php index f7fd80b4..9c5203e7 100644 --- a/data/web/inc/prerequisites.inc.php +++ b/data/web/inc/prerequisites.inc.php @@ -70,6 +70,7 @@ try { } } catch (Exception $e) { +// Stop when redis is not available http_response_code(500); ?>
Connection to Redis failed.

The following error was reported:
getMessage();?>
@@ -99,6 +100,7 @@ try { } catch (PDOException $e) { // Stop when SQL connection fails +http_response_code(500); ?>
Connection to database failed.

The following error was reported:
getMessage();?>
Connection to dockerapi container failed.

The following error was reported:
-