[Web] add f2b_banlist endpoint
This commit is contained in:
parent
cf239dd6b2
commit
e2e8fbe313
@ -16,6 +16,7 @@ import json
|
|||||||
import iptc
|
import iptc
|
||||||
import dns.resolver
|
import dns.resolver
|
||||||
import dns.exception
|
import dns.exception
|
||||||
|
import uuid
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
@ -94,6 +95,7 @@ def verifyF2boptions(f2boptions):
|
|||||||
verifyF2boption(f2boptions,'retry_window', 600)
|
verifyF2boption(f2boptions,'retry_window', 600)
|
||||||
verifyF2boption(f2boptions,'netban_ipv4', 32)
|
verifyF2boption(f2boptions,'netban_ipv4', 32)
|
||||||
verifyF2boption(f2boptions,'netban_ipv6', 128)
|
verifyF2boption(f2boptions,'netban_ipv6', 128)
|
||||||
|
verifyF2boption(f2boptions,'banlist_id', str(uuid.uuid4()))
|
||||||
|
|
||||||
def verifyF2boption(f2boptions, f2boption, f2bdefault):
|
def verifyF2boption(f2boptions, f2boption, f2bdefault):
|
||||||
f2boptions[f2boption] = f2boptions[f2boption] if f2boption in f2boptions and f2boptions[f2boption] is not None else f2bdefault
|
f2boptions[f2boption] = f2boptions[f2boption] if f2boption in f2boptions and f2boptions[f2boption] is not None else f2bdefault
|
||||||
|
@ -85,6 +85,8 @@ $cors_settings = cors('get');
|
|||||||
$cors_settings['allowed_origins'] = str_replace(", ", "\n", $cors_settings['allowed_origins']);
|
$cors_settings['allowed_origins'] = str_replace(", ", "\n", $cors_settings['allowed_origins']);
|
||||||
$cors_settings['allowed_methods'] = explode(", ", $cors_settings['allowed_methods']);
|
$cors_settings['allowed_methods'] = explode(", ", $cors_settings['allowed_methods']);
|
||||||
|
|
||||||
|
$f2b_data = fail2ban('get');
|
||||||
|
|
||||||
$template = 'admin.twig';
|
$template = 'admin.twig';
|
||||||
$template_data = [
|
$template_data = [
|
||||||
'tfa_data' => $tfa_data,
|
'tfa_data' => $tfa_data,
|
||||||
@ -101,7 +103,8 @@ $template_data = [
|
|||||||
'domains' => $domains,
|
'domains' => $domains,
|
||||||
'all_domains' => $all_domains,
|
'all_domains' => $all_domains,
|
||||||
'mailboxes' => $mailboxes,
|
'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'),
|
'q_data' => quarantine('settings'),
|
||||||
'qn_data' => quota_notification('get'),
|
'qn_data' => quota_notification('get'),
|
||||||
'rsettings_map' => file_get_contents('http://nginx:8081/settings.php'),
|
'rsettings_map' => file_get_contents('http://nginx:8081/settings.php'),
|
||||||
@ -112,6 +115,7 @@ $template_data = [
|
|||||||
'password_complexity' => password_complexity('get'),
|
'password_complexity' => password_complexity('get'),
|
||||||
'show_rspamd_global_filters' => @$_SESSION['show_rspamd_global_filters'],
|
'show_rspamd_global_filters' => @$_SESSION['show_rspamd_global_filters'],
|
||||||
'cors_settings' => $cors_settings,
|
'cors_settings' => $cors_settings,
|
||||||
|
'is_https' => isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on',
|
||||||
'lang_admin' => json_encode($lang['admin']),
|
'lang_admin' => json_encode($lang['admin']),
|
||||||
'lang_datatables' => json_encode($lang['datatables'])
|
'lang_datatables' => json_encode($lang['datatables'])
|
||||||
];
|
];
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
function fail2ban($_action, $_data = null) {
|
function fail2ban($_action, $_data = null, $_extra = null) {
|
||||||
global $redis;
|
global $redis;
|
||||||
$_data_log = $_data;
|
$_data_log = $_data;
|
||||||
switch ($_action) {
|
switch ($_action) {
|
||||||
@ -329,5 +329,68 @@ function fail2ban($_action, $_data = null) {
|
|||||||
'msg' => 'f2b_modified'
|
'msg' => 'f2b_modified'
|
||||||
);
|
);
|
||||||
break;
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2246,6 +2246,21 @@ function cors($action, $data = null) {
|
|||||||
break;
|
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) {
|
function get_logs($application, $lines = false) {
|
||||||
if ($lines === false) {
|
if ($lines === false) {
|
||||||
|
@ -371,3 +371,11 @@ function addTag(tagAddElem, tag = null){
|
|||||||
$(tagValuesElem).val(JSON.stringify(value_tags));
|
$(tagValuesElem).val(JSON.stringify(value_tags));
|
||||||
$(tagInputElem).val('');
|
$(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");
|
||||||
|
}
|
@ -504,6 +504,15 @@ if (isset($_GET['query'])) {
|
|||||||
$_SESSION['challenge'] = $WebAuthn->getChallenge();
|
$_SESSION['challenge'] = $WebAuthn->getChallenge();
|
||||||
return;
|
return;
|
||||||
break;
|
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'])) {
|
if (isset($_SESSION['mailcow_cc_role'])) {
|
||||||
switch ($category) {
|
switch ($category) {
|
||||||
@ -1324,6 +1333,9 @@ if (isset($_GET['query'])) {
|
|||||||
break;
|
break;
|
||||||
case "fail2ban":
|
case "fail2ban":
|
||||||
switch ($object) {
|
switch ($object) {
|
||||||
|
case 'banlist':
|
||||||
|
echo fail2ban('banlist', 'get', $extra);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
$data = fail2ban('get');
|
$data = fail2ban('get');
|
||||||
process_get_return($data);
|
process_get_return($data);
|
||||||
@ -1930,8 +1942,15 @@ if (isset($_GET['query'])) {
|
|||||||
process_edit_return(fwdhost('edit', array_merge(array('fwdhost' => $items), $attr)));
|
process_edit_return(fwdhost('edit', array_merge(array('fwdhost' => $items), $attr)));
|
||||||
break;
|
break;
|
||||||
case "fail2ban":
|
case "fail2ban":
|
||||||
|
switch ($object) {
|
||||||
|
case 'banlist':
|
||||||
|
process_edit_return(fail2ban('banlist', 'refresh', $items));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
process_edit_return(fail2ban('edit', array_merge(array('network' => $items), $attr)));
|
process_edit_return(fail2ban('edit', array_merge(array('network' => $items), $attr)));
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case "ui_texts":
|
case "ui_texts":
|
||||||
process_edit_return(customize('edit', 'ui_texts', $attr));
|
process_edit_return(customize('edit', 'ui_texts', $attr));
|
||||||
break;
|
break;
|
||||||
|
@ -147,6 +147,7 @@
|
|||||||
"change_logo": "Logo ändern",
|
"change_logo": "Logo ändern",
|
||||||
"configuration": "Konfiguration",
|
"configuration": "Konfiguration",
|
||||||
"convert_html_to_text": "Konvertiere HTML zu reinem Text",
|
"convert_html_to_text": "Konvertiere HTML zu reinem Text",
|
||||||
|
"copy_to_clipboard": "Text wurde in die Zwischenablage kopiert!",
|
||||||
"cors_settings": "CORS Einstellungen",
|
"cors_settings": "CORS Einstellungen",
|
||||||
"credentials_transport_warning": "<b>Warnung</b>: Das Hinzufügen einer neuen Regel bewirkt die Aktualisierung der Authentifizierungsdaten aller vorhandenen Einträge mit identischem Next Hop.",
|
"credentials_transport_warning": "<b>Warnung</b>: Das Hinzufügen einer neuen Regel bewirkt die Aktualisierung der Authentifizierungsdaten aller vorhandenen Einträge mit identischem Next Hop.",
|
||||||
"customer_id": "Kunde",
|
"customer_id": "Kunde",
|
||||||
@ -1019,6 +1020,7 @@
|
|||||||
"domain_removed": "Domain %s wurde entfernt",
|
"domain_removed": "Domain %s wurde entfernt",
|
||||||
"dovecot_restart_success": "Dovecot wurde erfolgreich neu gestartet",
|
"dovecot_restart_success": "Dovecot wurde erfolgreich neu gestartet",
|
||||||
"eas_reset": "ActiveSync Gerät des Benutzers %s wurde zurückgesetzt",
|
"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",
|
"f2b_modified": "Änderungen an Fail2ban-Parametern wurden gespeichert",
|
||||||
"forwarding_host_added": "Weiterleitungs-Host %s wurde hinzugefügt",
|
"forwarding_host_added": "Weiterleitungs-Host %s wurde hinzugefügt",
|
||||||
"forwarding_host_removed": "Weiterleitungs-Host %s wurde entfernt",
|
"forwarding_host_removed": "Weiterleitungs-Host %s wurde entfernt",
|
||||||
|
@ -151,6 +151,7 @@
|
|||||||
"change_logo": "Change logo",
|
"change_logo": "Change logo",
|
||||||
"configuration": "Configuration",
|
"configuration": "Configuration",
|
||||||
"convert_html_to_text": "Convert HTML to plain text",
|
"convert_html_to_text": "Convert HTML to plain text",
|
||||||
|
"copy_to_clipboard": "Text copied to clipboard!",
|
||||||
"cors_settings": "CORS Settings",
|
"cors_settings": "CORS Settings",
|
||||||
"credentials_transport_warning": "<b>Warning</b>: Adding a new transport map entry will update the credentials for all entries with a matching next hop column.",
|
"credentials_transport_warning": "<b>Warning</b>: Adding a new transport map entry will update the credentials for all entries with a matching next hop column.",
|
||||||
"customer_id": "Customer ID",
|
"customer_id": "Customer ID",
|
||||||
@ -1028,6 +1029,7 @@
|
|||||||
"domain_removed": "Domain %s has been removed",
|
"domain_removed": "Domain %s has been removed",
|
||||||
"dovecot_restart_success": "Dovecot was restarted successfully",
|
"dovecot_restart_success": "Dovecot was restarted successfully",
|
||||||
"eas_reset": "ActiveSync devices for user %s were reset",
|
"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",
|
"f2b_modified": "Changes to Fail2ban parameters have been saved",
|
||||||
"forwarding_host_added": "Forwarding host %s has been added",
|
"forwarding_host_added": "Forwarding host %s has been added",
|
||||||
"forwarding_host_removed": "Forwarding host %s has been removed",
|
"forwarding_host_removed": "Forwarding host %s has been removed",
|
||||||
|
@ -90,6 +90,15 @@
|
|||||||
{% if not f2b_data.active_bans and not f2b_data.perm_bans %}
|
{% if not f2b_data.active_bans and not f2b_data.perm_bans %}
|
||||||
<i>{{ lang.admin.no_active_bans }}</i>
|
<i>{{ lang.admin.no_active_bans }}</i>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
<form class="form-inline" data-id="f2b_banlist" role="form" method="post">
|
||||||
|
<div class="input-group mb-3">
|
||||||
|
<input type="text" class="form-control" aria-label="Banlist url" value="{{ f2b_banlist_url}}" id="banlist_url">
|
||||||
|
{% if is_https %}
|
||||||
|
<button class="btn btn-secondary" type="button" onclick="copyToClipboard('banlist_url')"><i class="bi bi-clipboard"></i></button>
|
||||||
|
{% endif %}
|
||||||
|
<button class="btn btn-secondary" type="button" data-action="edit_selected" data-item="{{ f2b_data.banlist_id }}" data-id="f2b_banlist" data-api-url='edit/fail2ban/banlist' data-api-attr='{}'><i class="bi bi-arrow-clockwise"></i></button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
{% for active_ban in f2b_data.active_bans %}
|
{% for active_ban in f2b_data.active_bans %}
|
||||||
<p>
|
<p>
|
||||||
<span class="badge fs-5 bg-info" style="padding:4px;font-size:85%;">
|
<span class="badge fs-5 bg-info" style="padding:4px;font-size:85%;">
|
||||||
|
Loading…
Reference in New Issue
Block a user