new_functions_and_fixes #1

Merged
gru merged 33 commits from new_functions_and_fixes into master 2025-11-03 14:35:20 +01:00
5 changed files with 168 additions and 103 deletions
Showing only changes of commit 72bf6eb9d1 - Show all commits

View File

@@ -35,15 +35,18 @@ def index():
backend_server_ports = request.form.getlist('backend_server_ports[]') backend_server_ports = request.form.getlist('backend_server_ports[]')
backend_server_maxconns = request.form.getlist('backend_server_maxconns[]') backend_server_maxconns = request.form.getlist('backend_server_maxconns[]')
# ACL # Custom ACL (NEW)
is_acl = 'add_acl' in request.form add_custom_acl = 'add_custom_acl' in request.form
acl_name = request.form.get('acl', '') custom_acl_name = request.form.get('custom_acl_name', '').strip() if add_custom_acl else ''
acl_action = request.form.get('acl_action', '') custom_acl_type = request.form.get('custom_acl_type', 'path_beg') if add_custom_acl else ''
acl_backend_name = request.form.get('backend_name_acl', '') custom_acl_value = request.form.get('custom_acl_value', '').strip() if add_custom_acl else ''
custom_acl_action = request.form.get('custom_acl_action', 'route') if add_custom_acl else ''
custom_acl_backend = request.form.get('custom_acl_backend', '').strip() if add_custom_acl else ''
custom_acl_redirect_url = request.form.get('custom_acl_redirect_url', '').strip() if add_custom_acl else ''
# SSL # SSL
use_ssl = 'ssl_checkbox' in request.form use_ssl = 'ssl_checkbox' in request.form
ssl_cert_path = request.form.get('ssl_cert_path', '/etc/haproxy/certs/haproxy.pem') ssl_cert_path = request.form.get('ssl_cert_path', '/app/ssl/haproxy-configurator.pem')
https_redirect = 'ssl_redirect_checkbox' in request.form https_redirect = 'ssl_redirect_checkbox' in request.form
# DOS Protection # DOS Protection
@@ -54,12 +57,6 @@ def index():
# Forward For # Forward For
forward_for = 'forward_for_check' in request.form forward_for = 'forward_for_check' in request.form
# Forbidden paths
is_forbidden_path = 'add_acl_path' in request.form
forbidden_name = request.form.get('forbidden_name', '')
allowed_ip = request.form.get('allowed_ip', '')
forbidden_path = request.form.get('forbidden_path', '')
# SQL Injection # SQL Injection
sql_injection_check = 'sql_injection_check' in request.form sql_injection_check = 'sql_injection_check' in request.form
@@ -69,14 +66,20 @@ def index():
# Remote uploads # Remote uploads
is_remote_upload = 'remote_uploads_check' in request.form is_remote_upload = 'remote_uploads_check' in request.form
# Path-based redirects # Webshells
is_webshells = 'webshells_check' in request.form
# Path-based redirects (legacy)
add_path_based = 'add_path_based' in request.form add_path_based = 'add_path_based' in request.form
redirect_domain_name = request.form.get('redirect_domain_name', '') redirect_domain_name = request.form.get('redirect_domain_name', '')
root_redirect = request.form.get('root_redirect', '') root_redirect = request.form.get('root_redirect', '')
redirect_to = request.form.get('redirect_to', '') redirect_to = request.form.get('redirect_to', '')
# Webshells # Forbidden paths (legacy)
is_webshells = 'webshells_check' in request.form is_forbidden_path = 'add_acl_path' in request.form
forbidden_name = request.form.get('forbidden_name', '')
allowed_ip = request.form.get('allowed_ip', '')
forbidden_path = request.form.get('forbidden_path', '')
# Build backend_servers list # Build backend_servers list
backend_servers = [] backend_servers = []
@@ -114,7 +117,13 @@ def index():
sticky_session = True sticky_session = True
sticky_session_type = request.form.get('sticky_session_type', 'cookie') sticky_session_type = request.form.get('sticky_session_type', 'cookie')
# Call update_haproxy_config with all parameters # Legacy ACL (unused, kept for compatibility)
is_acl = False
acl_name = ''
acl_action = ''
acl_backend_name = ''
# Call update_haproxy_config
message = update_haproxy_config( message = update_haproxy_config(
frontend_name=frontend_name, frontend_name=frontend_name,
frontend_ip=frontend_ip, frontend_ip=frontend_ip,
@@ -158,7 +167,14 @@ def index():
backend_ssl_redirect=backend_ssl_redirect, backend_ssl_redirect=backend_ssl_redirect,
ssl_redirect_backend_name=ssl_redirect_backend_name, ssl_redirect_backend_name=ssl_redirect_backend_name,
ssl_redirect_port=ssl_redirect_port, ssl_redirect_port=ssl_redirect_port,
frontend_hostname=frontend_hostname frontend_hostname=frontend_hostname,
add_custom_acl=add_custom_acl,
custom_acl_name=custom_acl_name,
custom_acl_type=custom_acl_type,
custom_acl_value=custom_acl_value,
custom_acl_action=custom_acl_action,
custom_acl_backend=custom_acl_backend,
custom_acl_redirect_url=custom_acl_redirect_url
) )
# Determine message type # Determine message type

View File

@@ -1,4 +1,5 @@
#!/bin/bash #!/bin/bash
git pull
docker compose down docker compose down
docker compose up --remove-orphans --build --no-deps --force-recreate docker compose up --remove-orphans --build --no-deps --force-recreate

View File

@@ -27,6 +27,7 @@
$('#forward_for_check'), $('#forward_for_check'),
$('#add_acl_path'), $('#add_acl_path'),
$('#add_path_based'), $('#add_path_based'),
$('#add_custom_acl'),
]; ];
const forbiddenFields = $('#forbidden_fields'); const forbiddenFields = $('#forbidden_fields');
@@ -47,22 +48,6 @@
protocolSelect?.addEventListener('change', onProtocolChange); protocolSelect?.addEventListener('change', onProtocolChange);
onProtocolChange(); onProtocolChange();
// ===== ACL FIELDS =====
const aclCheckbox = $('#add_acl');
const aclFields = $('#acl_fields');
aclCheckbox?.addEventListener('change', () => toggle(aclCheckbox.checked, aclFields));
// ===== GENERIC TOGGLE BINDER =====
const bindToggle = (checkboxSel, targetSel) => {
const cb = $(checkboxSel);
const target = $(targetSel);
cb?.addEventListener('change', () => toggle(cb.checked, target));
if (cb && target) toggle(cb.checked, target);
};
bindToggle('#add_path_based', '#base_redirect_fields');
bindToggle('#add_acl_path', '#forbidden_fields');
// ===== BACKEND SSL REDIRECT ===== // ===== BACKEND SSL REDIRECT =====
const backendSslCheckbox = $('#backend_ssl_redirect'); const backendSslCheckbox = $('#backend_ssl_redirect');
const backendSslFields = $('#backend_ssl_fields'); const backendSslFields = $('#backend_ssl_fields');
@@ -71,4 +56,27 @@
toggle(this.checked, backendSslFields); toggle(this.checked, backendSslFields);
}); });
// ===== CUSTOM ACL (Main Toggle) =====
const customAclCheckbox = $('#add_custom_acl');
const customAclFields = $('#custom_acl_fields');
customAclCheckbox?.addEventListener('change', function() {
toggle(this.checked, customAclFields);
});
// ===== CUSTOM ACL Action Type Toggle =====
const customAclAction = $('#custom_acl_action');
const aclBackendSelect = $('#acl_backend_select');
const aclRedirectSelect = $('#acl_redirect_select');
const onCustomAclActionChange = () => {
const action = customAclAction?.value;
toggle(action === 'route', aclBackendSelect);
toggle(action === 'redirect', aclRedirectSelect);
};
customAclAction?.addEventListener('change', onCustomAclActionChange);
// Initial state
onCustomAclActionChange();
})(); })();

View File

@@ -78,6 +78,15 @@
placeholder="80" min="1" max="65535" required> placeholder="80" min="1" max="65535" required>
</div> </div>
</div> </div>
<div class="row g-3 mb-3">
<div class="col-md-12">
<label for="frontend_hostname" class="form-label">Frontend Hostname (Domain)</label>
<input type="text" class="form-control" id="frontend_hostname" name="frontend_hostname"
placeholder="e.g. hosts.h.linuxiarz.pl" required>
<div class="form-text">Domain name for the ACL rule - traffic will be matched by Host header</div>
</div>
</div>
<div class="row g-3 mb-3"> <div class="row g-3 mb-3">
<div class="col-md-6"> <div class="col-md-6">
@@ -101,16 +110,6 @@
</div> </div>
</div> </div>
<div class="row g-3 mb-3">
<div class="col-md-12">
<label for="frontend_hostname" class="form-label">Frontend Hostname (Domain)</label>
<input type="text" class="form-control" id="frontend_hostname" name="frontend_hostname"
placeholder="e.g. hosts.h.linuxiarz.pl" required>
<div class="form-text">Domain name for the ACL rule - traffic will be matched by Host header</div>
</div>
</div>
<!-- SSL Section --> <!-- SSL Section -->
<div class="row g-3 mb-3"> <div class="row g-3 mb-3">
<div class="col-md-12"> <div class="col-md-12">
@@ -125,8 +124,9 @@
<div class="row g-3 mb-3 d-none" id="ssl_fields"> <div class="row g-3 mb-3 d-none" id="ssl_fields">
<div class="col-md-12"> <div class="col-md-12">
<label for="ssl_cert_path" class="form-label">SSL Certificate Path</label> <label for="ssl_cert_path" class="form-label">SSL Certificate Path
<small>Upload certs in /ssl/</small> <small>Upload certs in /ssl/</small></label>
<input type="text" class="form-control" id="ssl_cert_path" name="ssl_cert_path" <input type="text" class="form-control" id="ssl_cert_path" name="ssl_cert_path"
value="/app/ssl/haproxy-configurator.pem"> value="/app/ssl/haproxy-configurator.pem">
<div class="form-text">Full path to .pem file</div> <div class="form-text">Full path to .pem file</div>
@@ -142,6 +142,29 @@
</div> </div>
</div> </div>
<!-- Backend SSL Redirect -->
<div class="row g-3 mb-3">
<div class="col-md-12">
<div class="form-check">
<input class="form-check-input" type="checkbox" id="backend_ssl_redirect"
name="backend_ssl_redirect">
<label class="form-check-label" for="backend_ssl_redirect">
<i class="bi bi-arrow-repeat me-1"></i>Add HTTP Redirect to HTTPS
</label>
<div class="form-text small">Creates additional frontend on port 80 to redirect HTTP to HTTPS backend</div>
</div>
</div>
</div>
<div class="row g-3 mb-3 d-none" id="backend_ssl_fields">
<div class="col-md-12">
<label for="ssl_redirect_backend_name" class="form-label">Redirect Backend Name (HTTP → HTTPS)</label>
<input type="text" class="form-control" id="ssl_redirect_backend_name"
name="ssl_redirect_backend_name" placeholder="e.g. be_redirect">
<div class="form-text">Name for the redirect backend that will push traffic to HTTPS</div>
</div>
</div>
<hr class="my-4"> <hr class="my-4">
<!-- BACKEND SECTION --> <!-- BACKEND SECTION -->
@@ -369,79 +392,70 @@
<hr class="my-4"> <hr class="my-4">
<!-- ACL SECTION --> <!-- CUSTOM ACL SECTION (NEW) -->
<h6 class="text-primary mb-3"><i class="bi bi-diagram-3 me-2"></i>ACL & Routing</h6> <h6 class="text-primary mb-3"><i class="bi bi-shuffle me-2"></i>Custom ACL Rules (Advanced)</h6>
<div class="row g-3 mb-3 http-only"> <div class="row g-3 mb-3 http-only">
<div class="col-md-12"> <div class="col-md-12">
<div class="form-check"> <div class="form-check">
<input class="form-check-input" type="checkbox" id="add_acl" name="add_acl"> <input class="form-check-input" type="checkbox" id="add_custom_acl" name="add_custom_acl">
<label class="form-check-label" for="add_acl"> <label class="form-check-label" for="add_custom_acl">
<i class="bi bi-shuffle me-1"></i>Add ACL <i class="bi bi-sliders me-1"></i>Add Custom ACL Rule
</label> </label>
<div class="form-text small">Create additional routing or blocking rules beyond hostname matching</div>
</div> </div>
</div> </div>
<div class="col-md-4 d-none" id="acl_fields"> </div>
<input type="text" class="form-control" id="acl" name="acl" placeholder="acl_name">
<!-- Custom ACL Fields (Hidden by default) -->
<div class="row g-3 mb-3 http-only d-none" id="custom_acl_fields">
<div class="col-md-3">
<label for="custom_acl_name" class="form-label">ACL Name</label>
<input type="text" class="form-control" id="custom_acl_name" name="custom_acl_name"
placeholder="e.g. is_admin_path">
<div class="form-text small">Unique identifier for this rule</div>
</div> </div>
<div class="col-md-4 d-none" id="acl_fields">
<select class="form-select" id="acl_action" name="acl_action"> <div class="col-md-3">
<option value="hdr">Header</option> <label for="custom_acl_type" class="form-label">Rule Type</label>
<option value="path">Path</option> <select class="form-select" id="custom_acl_type" name="custom_acl_type">
<option value="path_beg">Path Begins With</option>
<option value="path_end">Path Ends With</option>
<option value="path_sub">Path Contains</option>
<option value="hdr">Header Contains</option>
<option value="src">Source IP</option> <option value="src">Source IP</option>
<option value="method">HTTP Method</option>
</select> </select>
</div> </div>
<div class="col-md-4 d-none" id="acl_fields">
<input type="text" class="form-control" id="backend_name_acl" name="backend_name_acl"
placeholder="backend_name">
</div>
</div>
<!-- Path-based routing --> <div class="col-md-3">
<div class="row g-3 mb-3 http-only"> <label for="custom_acl_value" class="form-label">Rule Value</label>
<div class="col-md-12"> <input type="text" class="form-control" id="custom_acl_value" name="custom_acl_value"
<div class="form-check"> placeholder="e.g. /admin, api, 192.168.1.0/24, GET">
<input class="form-check-input" type="checkbox" id="add_path_based" name="add_path_based"> <div class="form-text small">Value to match (path, header name, IP, method)</div>
<label class="form-check-label" for="add_path_based">
<i class="bi bi-arrow-repeat me-1"></i>Path-based Redirect
</label>
</div>
</div> </div>
<div class="col-md-4 d-none" id="base_redirect_fields">
<input type="text" class="form-control" id="redirect_domain_name" name="redirect_domain_name"
placeholder="domain.com">
</div>
<div class="col-md-4 d-none" id="base_redirect_fields">
<input type="text" class="form-control" id="root_redirect" name="root_redirect"
placeholder="/">
</div>
<div class="col-md-4 d-none" id="base_redirect_fields">
<input type="text" class="form-control" id="redirect_to" name="redirect_to"
placeholder="https://example.com">
</div>
</div>
<!-- Forbidden paths --> <div class="col-md-3">
<div class="row g-3 mb-3 http-only"> <label for="custom_acl_action" class="form-label">Action</label>
<div class="col-md-12"> <select class="form-select" id="custom_acl_action" name="custom_acl_action">
<div class="form-check"> <option value="route">Route to Backend</option>
<input class="form-check-input" type="checkbox" id="add_acl_path" name="add_acl_path"> <option value="deny">Block (Deny)</option>
<label class="form-check-label" for="add_acl_path"> <option value="redirect">Redirect</option>
<i class="bi bi-ban me-1"></i>Block Paths </select>
</label>
</div>
</div> </div>
<div class="col-md-4 d-none" id="forbidden_fields">
<input type="text" class="form-control" id="forbidden_name" name="forbidden_name" <div class="col-md-6 d-none" id="acl_backend_select">
placeholder="forbidden_acl"> <label for="custom_acl_backend" class="form-label">Target Backend</label>
<input type="text" class="form-control" id="custom_acl_backend" name="custom_acl_backend"
placeholder="e.g. be_admin">
<div class="form-text small">Backend to send matching traffic to</div>
</div> </div>
<div class="col-md-4 d-none" id="forbidden_fields">
<input type="text" class="form-control" id="allowed_ip" name="allowed_ip" <div class="col-md-6 d-none" id="acl_redirect_select">
placeholder="192.168.1.0/24"> <label for="custom_acl_redirect_url" class="form-label">Redirect URL</label>
</div> <input type="text" class="form-control" id="custom_acl_redirect_url" name="custom_acl_redirect_url"
<div class="col-md-4 d-none" id="forbidden_fields"> placeholder="e.g. https://example.com/new-path">
<input type="text" class="form-control" id="forbidden_path" name="forbidden_path" <div class="form-text small">URL to redirect matching requests to</div>
placeholder="/admin">
</div> </div>
</div> </div>

View File

@@ -87,7 +87,9 @@ def update_haproxy_config(frontend_name, frontend_ip, frontend_port, lb_method,
allowed_ip, forbidden_path, sql_injection_check, is_xss, is_remote_upload, allowed_ip, forbidden_path, sql_injection_check, is_xss, is_remote_upload,
add_path_based, redirect_domain_name, root_redirect, redirect_to, is_webshells, add_path_based, redirect_domain_name, root_redirect, redirect_to, is_webshells,
del_server_header=False, backend_ssl_redirect=False, ssl_redirect_backend_name='', del_server_header=False, backend_ssl_redirect=False, ssl_redirect_backend_name='',
ssl_redirect_port='80', frontend_hostname=''): ssl_redirect_port='80', frontend_hostname='', add_custom_acl=False,
custom_acl_name='', custom_acl_type='path_beg', custom_acl_value='',
custom_acl_action='route', custom_acl_backend='', custom_acl_redirect_url=''):
os.makedirs(os.path.dirname(HAPROXY_CFG), exist_ok=True) os.makedirs(os.path.dirname(HAPROXY_CFG), exist_ok=True)
@@ -174,6 +176,30 @@ def update_haproxy_config(frontend_name, frontend_ip, frontend_port, lb_method,
haproxy_cfg.write(" acl blocked_webshell path_reg -i /(cmd|shell|backdoor|webshell|phpspy|c99|kacak|b374k|log4j|log4shell|wsos|madspot|malicious|evil).*\\.php.*\n") haproxy_cfg.write(" acl blocked_webshell path_reg -i /(cmd|shell|backdoor|webshell|phpspy|c99|kacak|b374k|log4j|log4shell|wsos|madspot|malicious|evil).*\\.php.*\n")
haproxy_cfg.write(f" http-request deny if blocked_webshell\n") haproxy_cfg.write(f" http-request deny if blocked_webshell\n")
# ===== CUSTOM ACL RULES =====
if add_custom_acl and custom_acl_name and custom_acl_value:
# Write ACL rule based on type
if custom_acl_type == 'path_beg':
haproxy_cfg.write(f" acl {custom_acl_name} path_beg {custom_acl_value}\n")
elif custom_acl_type == 'path_end':
haproxy_cfg.write(f" acl {custom_acl_name} path_end {custom_acl_value}\n")
elif custom_acl_type == 'path_sub':
haproxy_cfg.write(f" acl {custom_acl_name} path_sub {custom_acl_value}\n")
elif custom_acl_type == 'hdr':
haproxy_cfg.write(f" acl {custom_acl_name} hdr_sub(host) -i {custom_acl_value}\n")
elif custom_acl_type == 'src':
haproxy_cfg.write(f" acl {custom_acl_name} src {custom_acl_value}\n")
elif custom_acl_type == 'method':
haproxy_cfg.write(f" acl {custom_acl_name} method {custom_acl_value}\n")
# Apply action based on type
if custom_acl_action == 'deny':
haproxy_cfg.write(f" http-request deny if {custom_acl_name}\n")
elif custom_acl_action == 'redirect' and custom_acl_redirect_url:
haproxy_cfg.write(f" http-request redirect location {custom_acl_redirect_url} if {custom_acl_name}\n")
elif custom_acl_action == 'route' and custom_acl_backend:
haproxy_cfg.write(f" use_backend {custom_acl_backend} if {custom_acl_name}\n")
# ===== BACKEND ROUTING ===== # ===== BACKEND ROUTING =====
if acl_name_sanitized: if acl_name_sanitized:
# Jeśli jest hostname, routuj z ACL # Jeśli jest hostname, routuj z ACL